Compare commits
11 Commits
dev
...
4466-factu
Author | SHA1 | Date |
---|---|---|
Carlos Andrés | 1989375368 | |
Alexandre Riera | efdf62438f | |
Alexandre Riera | 4ee50991d6 | |
Alexandre Riera | ca9e0a0f2a | |
Alexandre Riera | 179822583f | |
Alexandre Riera | e9487dee7b | |
Alexandre Riera | 08e6c435c6 | |
Alexandre Riera | 0b55e20dbe | |
Alexandre Riera | ba3e961942 | |
Alexandre Riera | 7568a5f47f | |
Alexandre Riera | a6894b88c1 |
|
@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||
## [2326.01] - 2023-06-29
|
||||
|
||||
### Added
|
||||
- (Tickets -> Crear Factura) Al facturar se envia automáticamente el pdf al cliente
|
||||
- (Facturas Recibidas -> Rectificativa) Nueva sección
|
||||
- (Entradas -> Correo) Al cambiar el tipo de cambio enviará un correo a las personas designadas
|
||||
|
||||
### Changed
|
||||
|
|
|
@ -0,0 +1,251 @@
|
|||
CREATE TABLE `vn`.`invoiceInCorrection` (
|
||||
`correctingFk` mediumint(8) unsigned NOT NULL COMMENT 'Factura rectificativa',
|
||||
`correctedFk` mediumint(8) unsigned NOT NULL COMMENT 'Factura rectificada',
|
||||
`cplusRectificationTypeFk` int(10) unsigned NOT NULL,
|
||||
`cplusInvoiceType477Fk` int(10) unsigned NOT NULL,
|
||||
`invoiceCorrectionTypeFk` int(11) NOT NULL DEFAULT 3,
|
||||
PRIMARY KEY (`correctingFk`),
|
||||
KEY `invoiceInCorrection_correctedFk` (`correctedFk`),
|
||||
KEY `invoiceInCorrection_cplusRectificationTypeFk` (`cplusRectificationTypeFk`),
|
||||
KEY `invoiceInCorrection_cplusInvoiceType477Fk` (`cplusInvoiceType477Fk`),
|
||||
KEY `invoiceInCorrection_invoiceCorrectionTypeFk` (`invoiceCorrectionTypeFk`),
|
||||
CONSTRAINT `invoiceInCorrection_correctedFk` FOREIGN KEY (`correctedFk`) REFERENCES `invoiceIn` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT `invoiceInCorrection_correctingFk` FOREIGN KEY (`correctingFk`) REFERENCES `invoiceIn` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT `invoiceInCorrection_cplusInvoiceType477Fk` FOREIGN KEY (`cplusInvoiceType477Fk`) REFERENCES `cplusInvoiceType477` (`id`) ON UPDATE CASCADE,
|
||||
CONSTRAINT `invoiceInCorrection_invoiceCorrectionTypeFk` FOREIGN KEY (`invoiceCorrectionTypeFk`) REFERENCES `invoiceCorrectionType` (`id`) ON UPDATE CASCADE,
|
||||
CONSTRAINT `invoiceInCorrection_cplusRectificationTypeFk` FOREIGN KEY (`cplusRectificationTypeFk`) REFERENCES `cplusRectificationType` (`id`) ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci COMMENT='Relacion entre las facturas rectificativas y las rectificadas.';
|
||||
|
||||
|
||||
INSERT INTO `salix`.`ACL` (`model`, `property`, `accessType`, `permission`, `principalType`, `principalId`)
|
||||
VALUES
|
||||
('InvoiceInCorrection', '*', '*', 'ALLOW', 'ROLE', 'administrative'),
|
||||
('InvoiceCorrectionType', '*', '*', 'ALLOW', 'ROLE', 'administrative'),
|
||||
('CplusInvoiceType477', '*', '*', 'ALLOW', 'ROLE', 'administrative'),
|
||||
('CplusRectificationType', '*', '*', 'ALLOW', 'ROLE', 'administrative');
|
||||
|
||||
|
||||
DROP PROCEDURE IF EXISTS sage.invoiceIn_add;
|
||||
|
||||
DELIMITER $$
|
||||
$$
|
||||
CREATE DEFINER=`root`@`localhost` PROCEDURE `sage`.`invoiceIn_add`(vInvoiceInFk INT, vXDiarioFk INT)
|
||||
BEGIN
|
||||
/**
|
||||
* Traslada la info de contabilidad relacionada con las facturas recibidas
|
||||
*
|
||||
* @vInvoiceInFk Factura recibida
|
||||
* @vXDiarioFk Id tabla XDiario
|
||||
*/
|
||||
DECLARE vDone BOOL DEFAULT FALSE;
|
||||
DECLARE vBase DOUBLE;
|
||||
DECLARE vVat DOUBLE;
|
||||
DECLARE vRate DOUBLE;
|
||||
DECLARE vTransactionCode INT;
|
||||
DECLARE vCounter INT DEFAULT 0;
|
||||
DECLARE vTransactionCodeOld INT;
|
||||
DECLARE vTaxCode INT;
|
||||
DECLARE vTaxCodeOld INT;
|
||||
DECLARE vOperationCode VARCHAR(1);
|
||||
DECLARE vIsIntracommunity BOOL DEFAULT FALSE;
|
||||
DECLARE vSerialDua VARCHAR(1) DEFAULT 'D';
|
||||
DECLARE vInvoiceTypeReceived VARCHAR(1);
|
||||
DECLARE vInvoiceTypeInformative VARCHAR(1);
|
||||
DECLARE vInvoiceInOriginalFk INT;
|
||||
|
||||
DECLARE vCursor CURSOR FOR
|
||||
SELECT it.taxableBase,
|
||||
CAST((( it.taxableBase / 100) * t.PorcentajeIva) AS DECIMAL (10,2)),
|
||||
t.PorcentajeIva,
|
||||
it.transactionTypeSageFk,
|
||||
it.taxTypeSageFk,
|
||||
t.isIntracommunity,
|
||||
tt.ClaveOperacionDefecto
|
||||
FROM vn.invoiceIn i
|
||||
JOIN vn.invoiceInTax it ON it.InvoiceInFk = i.id
|
||||
JOIN TiposIva t ON t.CodigoIva = it.taxTypeSageFk
|
||||
JOIN TiposTransacciones tt ON tt.CodigoTransaccion = it.transactionTypeSageFk
|
||||
LEFT JOIN vn.dua d ON d.id = vInvoiceInFk
|
||||
WHERE i.id = vInvoiceInFk
|
||||
AND d.id IS NULL;
|
||||
|
||||
DECLARE CONTINUE HANDLER FOR NOT FOUND SET vDone = TRUE;
|
||||
|
||||
DELETE FROM movContaIVA
|
||||
WHERE id = vXDiarioFk;
|
||||
|
||||
SELECT codeSage INTO vInvoiceTypeReceived
|
||||
FROM invoiceType WHERE code ='received';
|
||||
|
||||
SELECT codeSage INTO vInvoiceTypeInformative
|
||||
FROM invoiceType WHERE code ='informative';
|
||||
|
||||
INSERT INTO movContaIVA(id, LibreA1)
|
||||
VALUES (vXDiarioFk, vInvoiceInFk);
|
||||
|
||||
SELECT invoiceInOriginalFk INTO vInvoiceInOriginalFk
|
||||
FROM vn.invoiceInRefund
|
||||
WHERE invoiceInRefundFk = vInvoiceInFk;
|
||||
|
||||
IF vInvoiceInOriginalFk THEN
|
||||
|
||||
UPDATE movContaIVA mci
|
||||
JOIN vn.invoiceInRefund iir ON iir.invoiceInRefundFk = vInvoiceInFk
|
||||
JOIN (SELECT issued,
|
||||
SUM(sub.taxableBase) taxableBase,
|
||||
SUM(ROUND((sub.taxableBase * sub.PorcentajeIva) / 100 , 2)) vat
|
||||
FROM (SELECT issued,
|
||||
SUM(iit.taxableBase) taxableBase,
|
||||
ti.PorcentajeIva
|
||||
FROM vn.invoiceIn i
|
||||
JOIN vn.invoiceInTax iit ON iit.invoiceInFk = i.id
|
||||
JOIN sage.TiposIva ti ON ti.CodigoIva = iit.taxTypeSageFk
|
||||
WHERE i.id = vInvoiceInOriginalFk
|
||||
GROUP BY ti.CodigoIva)sub
|
||||
) invoiceInOriginal
|
||||
JOIN ClavesOperacion co ON co.Descripcion = 'Factura rectificativa'
|
||||
SET mci.TipoRectificativa = iir.refundCategoryFk,
|
||||
mci.ClaseAbonoRectificativas = iir.refundType,
|
||||
mci.FechaFacturaOriginal = invoiceInOriginal.issued,
|
||||
mci.FechaOperacion = invoiceInOriginal.issued,
|
||||
mci.BaseImponibleOriginal = invoiceInOriginal.taxableBase,
|
||||
mci.CuotaIvaOriginal = invoiceInOriginal.vat,
|
||||
mci.ClaveOperacionFactura = co.ClaveOperacionFactura_
|
||||
WHERE mci.id = vXDiarioFk;
|
||||
|
||||
END IF;
|
||||
|
||||
OPEN vCursor;
|
||||
|
||||
l: LOOP
|
||||
FETCH vCursor INTO vBase,
|
||||
vVat,
|
||||
vRate,
|
||||
vTransactionCode,
|
||||
vTaxCode,
|
||||
vIsIntracommunity,
|
||||
vOperationCode;
|
||||
|
||||
IF vDone THEN
|
||||
LEAVE l;
|
||||
END IF;
|
||||
|
||||
SET vTransactionCodeOld = vTransactionCode;
|
||||
SET vTaxCodeOld = vTaxCode;
|
||||
|
||||
IF vOperationCode IS NOT NULL THEN
|
||||
UPDATE movContaIVA
|
||||
SET ClaveOperacionFactura = vOperationCode
|
||||
WHERE id = vXDiarioFk;
|
||||
END IF;
|
||||
|
||||
SET vCounter = vCounter + 1;
|
||||
CASE vCounter
|
||||
WHEN 1 THEN
|
||||
UPDATE movContaIVA
|
||||
SET BaseIva1 = vBase,
|
||||
PorIva1 = vRate,
|
||||
CuotaIva1 = vVat,
|
||||
CodigoTransaccion1 = vTransactionCode,
|
||||
CodigoIva1 = vTaxCode
|
||||
WHERE id = vXDiarioFk;
|
||||
|
||||
WHEN 2 THEN
|
||||
UPDATE movContaIVA
|
||||
SET BaseIva2 = vBase,
|
||||
PorIva2 = vRate,
|
||||
CuotaIva2 = vVat,
|
||||
CodigoTransaccion2 = vTransactionCode,
|
||||
CodigoIva2 = vTaxCode
|
||||
WHERE id = vXDiarioFk;
|
||||
WHEN 3 THEN
|
||||
UPDATE movContaIVA
|
||||
SET BaseIva3 = vBase,
|
||||
PorIva3 = vRate,
|
||||
CuotaIva3 = vVat,
|
||||
CodigoTransaccion3 = vTransactionCode,
|
||||
CodigoIva3 = vTaxCode
|
||||
WHERE id = vXDiarioFk;
|
||||
WHEN 4 THEN
|
||||
UPDATE movContaIVA
|
||||
SET BaseIva4 = vBase,
|
||||
PorIva4 = vRate,
|
||||
CuotaIva4 = vVat,
|
||||
CodigoTransaccion4 = vTransactionCode,
|
||||
CodigoIva4 = vTaxCode
|
||||
WHERE id = vXDiarioFk;
|
||||
ELSE
|
||||
SELECT vXDiarioFk INTO vXDiarioFk;
|
||||
END CASE;
|
||||
|
||||
IF vIsIntracommunity THEN
|
||||
UPDATE movContaIVA
|
||||
SET Intracomunitaria = TRUE
|
||||
WHERE id = vXDiarioFk;
|
||||
END IF;
|
||||
|
||||
SET vTransactionCodeOld = vTransactionCode;
|
||||
SET vTaxCodeOld = vTaxCode;
|
||||
|
||||
END LOOP;
|
||||
|
||||
CLOSE vCursor;
|
||||
|
||||
UPDATE movContaIVA mci
|
||||
JOIN tmp.invoiceIn ii ON ii.id = vInvoiceInFk
|
||||
JOIN vn.XDiario x ON x.id = mci.id
|
||||
LEFT JOIN tmp.invoiceDua id ON id.id = mci.id
|
||||
JOIN vn.supplier s ON s.id = ii.supplierFk
|
||||
JOIN Naciones n ON n.countryFk = s.countryFk
|
||||
SET mci.CodigoDivisa = ii.currencyFk,
|
||||
mci.Año = YEAR(ii.issued),
|
||||
mci.Serie = ii.serial,
|
||||
mci.Factura = ii.serialNumber,
|
||||
mci.FechaFactura = ii.issued,
|
||||
mci.ImporteFactura = IFNULL(mci.BaseIva1, 0) + IFNULL(mci.CuotaIva1, 0) +
|
||||
IFNULL(mci.BaseIva2, 0) + IFNULL(mci.CuotaIva2, 0) +
|
||||
IFNULL(mci.BaseIva3, 0) + IFNULL(mci.CuotaIva3, 0) +
|
||||
IFNULL(mci.BaseIva4, 0) + IFNULL(mci.CuotaIva4, 0),
|
||||
mci.TipoFactura = IF(id.id, IF( ii.serial = vSerialDua COLLATE utf8mb3_unicode_ci, vInvoiceTypeReceived, vInvoiceTypeInformative), vInvoiceTypeReceived),
|
||||
mci.CodigoCuentaFactura = x.SUBCTA,
|
||||
mci.CifDni = IF(LEFT(TRIM(s.nif), 2) = n.SiglaNacion, SUBSTRING(TRIM(s.nif), 3), s.nif),
|
||||
mci.Nombre = s.name,
|
||||
mci.SiglaNacion = n.SiglaNacion,
|
||||
mci.EjercicioFactura = YEAR(ii.issued),
|
||||
mci.FechaOperacion = ii.issued,
|
||||
mci.MantenerAsiento = TRUE,
|
||||
mci.SuFacturaNo = ii.supplierRef,
|
||||
mci.IvaDeducible1 = IF(id.id, FALSE, IF(IFNULL(mci.BaseIva1, FALSE) = FALSE, FALSE, ii.isVatDeductible)),
|
||||
mci.IvaDeducible2 = IF(id.id, FALSE, IF(IFNULL(mci.BaseIva2, FALSE) = FALSE, FALSE, ii.isVatDeductible)),
|
||||
mci.IvaDeducible3 = IF(id.id, FALSE, IF(IFNULL(mci.BaseIva3, FALSE) = FALSE, FALSE, ii.isVatDeductible)),
|
||||
mci.IvaDeducible4 = IF(id.id, FALSE, IF(IFNULL(mci.BaseIva4, FALSE) = FALSE, FALSE, ii.isVatDeductible)),
|
||||
mci.FechaFacturaOriginal = x.FECHA_EX
|
||||
WHERE mci.id = vXDiarioFk;
|
||||
|
||||
-- RETENCIONES
|
||||
UPDATE movContaIVA mci
|
||||
JOIN vn.invoiceIn ii ON ii.id = vInvoiceInFk
|
||||
JOIN vn.XDiario x ON x.id = mci.id
|
||||
JOIN vn.supplier s ON s.id = supplierFk
|
||||
JOIN vn.invoiceInTax iit ON iit.invoiceInFk = ii.id
|
||||
JOIN vn.expence e ON e.id = iit.expenceFk
|
||||
JOIN TiposRetencion t ON t.CodigoRetencion = ii.withholdingSageFk
|
||||
LEFT JOIN tmp.invoiceDua id ON id.id = mci.id
|
||||
JOIN (SELECT SUM(x2.BASEEURO) taxableBase, SUM(x2.EURODEBE) taxBase
|
||||
FROM vn.XDiario x1
|
||||
JOIN vn.XDiario x2 ON x1.ASIEN = x2.ASIEN
|
||||
WHERE x2.BASEEURO <> 0
|
||||
AND x1.id = vXDiarioFk
|
||||
)sub
|
||||
JOIN ClavesOperacion co ON co.Descripcion = 'Arrendamiento de locales de negocio'
|
||||
SET mci.CodigoRetencion = t.CodigoRetencion,
|
||||
mci.ClaveOperacionFactura = IF( t.Retencion = 'ARRENDAMIENTO Y SUBARRENDAMIENTO', co.ClaveOperacionFactura_, mci.ClaveOperacionFactura),
|
||||
mci.BaseRetencion = IF (t.Retencion = 'ACTIVIDADES AGRICOLAS O GANADERAS', sub.taxableBase + sub.taxBase, sub.taxableBase),
|
||||
mci.PorRetencion = t.PorcentajeRetencion,
|
||||
mci.ImporteRetencion = iit.taxableBase * - 1
|
||||
WHERE mci.id = vXDiarioFk
|
||||
AND e.name = 'Retenciones'
|
||||
AND id.id IS NULL;
|
||||
|
||||
END$$
|
||||
DELIMITER ;
|
|
@ -2867,6 +2867,12 @@ INSERT INTO `vn`.`deviceProductionUser` (`deviceProductionFk`, `userFk`, `create
|
|||
(1, 1, util.VN_NOW()),
|
||||
(3, 3, util.VN_NOW());
|
||||
|
||||
INSERT INTO `vn`.`invoiceCorrectionType` (`id`, `description`)
|
||||
VALUES
|
||||
(1, 'Error en los datos del cliente'),
|
||||
(2, 'Error en el cálculo del IVA'),
|
||||
(3, 'Error en el detalle de las ventas');
|
||||
|
||||
INSERT INTO `vn`.`workerTimeControlMail` (`id`, `workerFk`, `year`, `week`, `state`, `updated`, `sendedCounter`, `reason`)
|
||||
VALUES
|
||||
(1, 9, 2000, 49, 'REVISE', util.VN_NOW(), 1, 'test2'),
|
||||
|
@ -2895,6 +2901,16 @@ INSERT INTO `vn`.`wagonTypeTray` (`id`, `typeFk`, `height`, `colorFk`)
|
|||
(2, 1, 50, 2),
|
||||
(3, 1, 0, 3);
|
||||
|
||||
INSERT INTO `vn`.`cplusRectificationType` (`id`, `description`)
|
||||
VALUES
|
||||
(1, 'Campo vacio'),
|
||||
(2, 'I - Por diferencias'),
|
||||
(3, 'S - Por sustitución');
|
||||
|
||||
INSERT INTO `vn`.`invoiceInCorrection` (`correctingFk`, `correctedFk`, `cplusRectificationTypeFk`, `cplusInvoiceType477Fk`, `invoiceCorrectionTypeFk`)
|
||||
VALUES
|
||||
(2, 3, 1, 1, 1);
|
||||
|
||||
INSERT INTO `salix`.`accessTokenConfig` (`id`, `renewPeriod`, `renewInterval`)
|
||||
VALUES
|
||||
(1, 21600, 300);
|
||||
|
|
|
@ -1017,14 +1017,27 @@ export default {
|
|||
},
|
||||
invoiceInSummary: {
|
||||
totalTaxableBase: 'vn-invoice-in-summary > vn-card > vn-horizontal > vn-auto > vn-horizontal > vn-one.taxes > span',
|
||||
supplierRef: 'vn-invoice-in-summary vn-label-value:nth-child(2) > section > span'
|
||||
supplierRef: 'vn-invoice-in-summary vn-label-value:nth-child(2) > section > span',
|
||||
correction: 'vn-invoice-in-summary > vn-card > vn-horizontal > vn-one[ng-if="$ctrl.summary.invoiceInCorrecting"]'
|
||||
},
|
||||
invoiceInCorrection: {
|
||||
add: 'vn-invoice-in-correction vn-icon-button[vn-tooltip="Add correction"]',
|
||||
originInvoice: 'vn-invoice-in-correction vn-autocomplete[vn-id="originInvoice"]',
|
||||
type: 'vn-invoice-in-correction vn-autocomplete[vn-id="type"]',
|
||||
class: 'vn-invoice-in-correction vn-autocomplete[vn-id="class"]',
|
||||
reason: 'vn-invoice-in-correction vn-autocomplete[vn-id="reason"]',
|
||||
deleteButton: 'vn-invoice-in-correction vn-icon-button[icon="delete"]',
|
||||
saveButton: 'vn-invoice-in-correction vn-submit',
|
||||
},
|
||||
invoiceInDescriptor: {
|
||||
summaryIcon: 'vn-invoice-in-descriptor a[title="Go to module summary"]',
|
||||
moreMenu: 'vn-invoice-in-descriptor vn-icon-button[icon=more_vert]',
|
||||
moreMenuDeleteInvoiceIn: '.vn-menu [name="deleteInvoice"]',
|
||||
moreMenuCloneInvoiceIn: '.vn-menu [name="cloneInvoice"]',
|
||||
acceptButton: '.vn-confirm.shown button[response="accept"]'
|
||||
acceptButton: '.vn-confirm.shown button[response="accept"]',
|
||||
supplierRef: 'vn-invoice-in-descriptor h5',
|
||||
correctedInvoice: 'vn-invoice-in-descriptor a[vn-tooltip="Corrected invoice"]',
|
||||
originInvoice: 'vn-invoice-in-descriptor a[vn-tooltip="Origin invoice"]'
|
||||
},
|
||||
invoiceInBasicData: {
|
||||
issued: 'vn-invoice-in-basic-data vn-date-picker[ng-model="$ctrl.invoiceIn.issued"]',
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
import selectors from '../../helpers/selectors.js';
|
||||
import getBrowser from '../../helpers/puppeteer.js';
|
||||
|
||||
describe('InvoiceIn correction path', () => {
|
||||
let browser;
|
||||
let page;
|
||||
|
||||
beforeAll(async() => {
|
||||
browser = await getBrowser();
|
||||
page = browser.page;
|
||||
await page.loginAndModule('administrative', 'invoiceIn');
|
||||
await page.accessToSearchResult('2');
|
||||
});
|
||||
|
||||
afterAll(async() => {
|
||||
await browser.close();
|
||||
});
|
||||
|
||||
it('should reach the summary section and check that contain a correction', async() => {
|
||||
await page.waitForSelector(selectors.invoiceInSummary.correction);
|
||||
await page.waitToClick(selectors.invoiceInDescriptor.correctedInvoice);
|
||||
const result = await page.waitToGetProperty(selectors.invoiceInDescriptor.supplierRef, 'innerText');
|
||||
|
||||
expect(result).toContain('1236');
|
||||
await page.waitToClick(selectors.invoiceInDescriptor.originInvoice);
|
||||
});
|
||||
|
||||
it('should go to correction section, delete the correction and save', async() => {
|
||||
await page.accessToSection('invoiceIn.card.correction');
|
||||
await page.waitToClick(selectors.invoiceInCorrection.deleteButton);
|
||||
await page.waitToClick(selectors.invoiceInCorrection.saveButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('Data saved!');
|
||||
});
|
||||
|
||||
it('should create a new correction', async() => {
|
||||
await page.reloadSection('invoiceIn.card.correction');
|
||||
await page.waitToClick(selectors.invoiceInCorrection.add);
|
||||
await page.autocompleteSearch(selectors.invoiceInCorrection.originInvoice, '1238');
|
||||
await page.autocompleteSearch(selectors.invoiceInCorrection.type, 'Sustitución');
|
||||
await page.autocompleteSearch(selectors.invoiceInCorrection.class, 'Ticket');
|
||||
await page.autocompleteSearch(selectors.invoiceInCorrection.reason, 'IVA');
|
||||
await page.waitToClick(selectors.invoiceInCorrection.saveButton);
|
||||
const message = await page.waitForSnackbar();
|
||||
|
||||
expect(message.text).toContain('Data saved!');
|
||||
});
|
||||
|
||||
it('should go to the new correction summary and check it has changed', async() => {
|
||||
await page.waitToClick(selectors.invoiceInDescriptor.correctedInvoice);
|
||||
const result = await page.waitToGetProperty(selectors.invoiceInDescriptor.supplierRef, 'innerText');
|
||||
|
||||
expect(result).toContain('1238');
|
||||
});
|
||||
});
|
|
@ -151,10 +151,12 @@
|
|||
"It is not possible to modify tracked sales": "It is not possible to modify tracked sales",
|
||||
"It is not possible to modify sales that their articles are from Floramondo": "It is not possible to modify sales that their articles are from Floramondo",
|
||||
"It is not possible to modify cloned sales": "It is not possible to modify cloned sales",
|
||||
"Valid priorities: 1,2,3": "Valid priorities: 1,2,3",
|
||||
"Origin invoice cannot be empty": "Origin invoice cannot be empty",
|
||||
"Warehouse inventory not set": "Almacén inventario no está establecido",
|
||||
"Component cost not set": "Componente coste no está estabecido",
|
||||
"Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº 2": "Tickets with associated refunds can't be deleted. This ticket is associated with refund Nº 2",
|
||||
"Type cannot be empty": "Type cannot be empty",
|
||||
"Class cannot be empty": "Class cannot be empty",
|
||||
"Reason cannot be empty": "Reason cannot be empty",
|
||||
"Description cannot be blank": "Description cannot be blank",
|
||||
"company": "Company",
|
||||
"country": "Country",
|
||||
|
|
|
@ -290,8 +290,12 @@
|
|||
"isTaxDataChecked": "Datos comprobados",
|
||||
"comercialId": "Id comercial",
|
||||
"comercialName": "Comercial",
|
||||
"Pass expired": "La contraseña ha caducado, cambiela desde Salix",
|
||||
"Invalid NIF for VIES": "Invalid NIF for VIES",
|
||||
"Origin invoice cannot be empty": "La factura origen no puede estar vacía",
|
||||
"Type cannot be empty": "El tipo no puede estar vacío",
|
||||
"Class cannot be empty": "La clase no puede estar vacía",
|
||||
"Reason cannot be empty": "El motivo no puede estar vacío",
|
||||
"Pass expired": "La contraseña ha caducado, cambiela desde Salix",
|
||||
"Ticket does not exist": "Este ticket no existe",
|
||||
"Ticket is already signed": "Este ticket ya ha sido firmado",
|
||||
"The renew period has not been exceeded": "El periodo de renovación no ha sido superado"
|
||||
|
|
|
@ -128,6 +128,37 @@ module.exports = Self => {
|
|||
scope: {
|
||||
fields: ['id', 'code']
|
||||
|
||||
}
|
||||
},
|
||||
{
|
||||
relation: 'invoiceInCorrecting',
|
||||
scope: {
|
||||
fields: ['correctedFk',
|
||||
'cplusInvoiceType477Fk',
|
||||
'invoiceCorrectionTypeFk',
|
||||
'cplusRectificationTypeFk'],
|
||||
include: [{
|
||||
relation: 'corrected',
|
||||
scope: {
|
||||
fields: ['supplierRef']
|
||||
}
|
||||
}, {
|
||||
relation: 'cplusInvoiceType477',
|
||||
scope: {
|
||||
fields: ['description']
|
||||
}
|
||||
}, {
|
||||
relation: 'invoiceCorrectionType',
|
||||
scope: {
|
||||
fields: ['description']
|
||||
}
|
||||
}, {
|
||||
relation: 'cplusRectificationType',
|
||||
scope: {
|
||||
fields: ['description']
|
||||
}
|
||||
}]
|
||||
|
||||
}
|
||||
}
|
||||
]
|
||||
|
|
|
@ -16,5 +16,17 @@
|
|||
},
|
||||
"InvoiceInTax": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"InvoiceInCorrection": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"InvoiceCorrectionType": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"CplusInvoiceType477": {
|
||||
"dataSource": "vn"
|
||||
},
|
||||
"CplusRectificationType": {
|
||||
"dataSource": "vn"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "CplusInvoiceType477",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "cplusInvoiceType477"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"description": "Identifier"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "CplusRectificationType",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "cplusRectificationType"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"description": "Identifier"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"name": "InvoiceCorrectionType",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "invoiceCorrectionType"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"id": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"description": "Identifier"
|
||||
},
|
||||
"description": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
module.exports = Self => {
|
||||
Self.validatesPresenceOf('correctedFk', {
|
||||
message: 'Origin invoice cannot be empty'
|
||||
});
|
||||
Self.validatesPresenceOf('cplusRectificationTypeFk', {
|
||||
message: 'Type cannot be empty'
|
||||
});
|
||||
Self.validatesPresenceOf('cplusInvoiceType477Fk', {
|
||||
message: 'Class cannot be empty'
|
||||
});
|
||||
Self.validatesPresenceOf('invoiceCorrectionTypeFk', {
|
||||
message: 'Reason cannot be empty'
|
||||
});
|
||||
};
|
|
@ -0,0 +1,57 @@
|
|||
{
|
||||
"name": "InvoiceInCorrection",
|
||||
"base": "VnModel",
|
||||
"options": {
|
||||
"mysql": {
|
||||
"table": "invoiceInCorrection"
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"correctingFk": {
|
||||
"id": true,
|
||||
"type": "number",
|
||||
"description": "Identifier"
|
||||
},
|
||||
"correctedFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"cplusRectificationTypeFk": {
|
||||
"type": "number"
|
||||
},
|
||||
"cplusInvoiceType477Fk": {
|
||||
"type": "number"
|
||||
},
|
||||
"invoiceCorrectionTypeFk": {
|
||||
"type": "number"
|
||||
}
|
||||
},
|
||||
"relations": {
|
||||
"correcting": {
|
||||
"type": "belongsTo",
|
||||
"model": "InvoiceIn",
|
||||
"foreignKey": "correctingFk"
|
||||
},
|
||||
"corrected": {
|
||||
"type": "belongsTo",
|
||||
"model": "InvoiceIn",
|
||||
"foreignKey": "correctedFk"
|
||||
},
|
||||
"cplusInvoiceType477": {
|
||||
"type": "belongsTo",
|
||||
"model": "CplusInvoiceType477",
|
||||
"foreignKey": "cplusInvoiceType477Fk"
|
||||
},
|
||||
"invoiceCorrectionType": {
|
||||
"type": "belongsTo",
|
||||
"model": "InvoiceCorrectionType",
|
||||
"foreignKey": "invoiceCorrectionTypeFk"
|
||||
},
|
||||
"cplusRectificationType": {
|
||||
"type": "belongsTo",
|
||||
"model": "CplusRectificationType",
|
||||
"foreignKey": "cplusRectificationTypeFk"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -61,6 +61,16 @@
|
|||
"model": "InvoiceInDueDay",
|
||||
"foreignKey": "invoiceInFk"
|
||||
},
|
||||
"invoiceInCorrecting": {
|
||||
"type": "hasOne",
|
||||
"model": "InvoiceInCorrection",
|
||||
"foreignKey": "correctingFk"
|
||||
},
|
||||
"invoiceInCorrected": {
|
||||
"type": "hasOne",
|
||||
"model": "InvoiceInCorrection",
|
||||
"foreignKey": "correctedFk"
|
||||
},
|
||||
"invoiceInIntrastat": {
|
||||
"type": "hasMany",
|
||||
"model": "InvoiceInIntrastat",
|
||||
|
|
|
@ -26,7 +26,14 @@ class Controller extends ModuleCard {
|
|||
},
|
||||
{
|
||||
relation: 'currency'
|
||||
},
|
||||
{
|
||||
relation: 'invoiceInCorrecting'
|
||||
},
|
||||
{
|
||||
relation: 'invoiceInCorrected'
|
||||
}
|
||||
|
||||
]};
|
||||
|
||||
this.$http.get(`InvoiceIns/${this.$params.id}`, {filter})
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
<vn-crud-model
|
||||
vn-id="model"
|
||||
url="InvoiceInCorrections"
|
||||
where="{correctingFk: $ctrl.$params.id}"
|
||||
data="$ctrl.corrections"
|
||||
auto-load="true"
|
||||
primary-key="correctingFk">
|
||||
</vn-crud-model>
|
||||
<vn-watcher
|
||||
vn-id="watcher"
|
||||
data="$ctrl.corrections"
|
||||
form="form">
|
||||
</vn-watcher>
|
||||
<form name="form" ng-submit="$ctrl.onSubmit()">
|
||||
<vn-card class="vn-pa-lg">
|
||||
<vn-horizontal ng-repeat="invoiceInCorrection in $ctrl.corrections">
|
||||
<vn-autocomplete vn-one vn-id="originInvoice"
|
||||
label="Origin invoice"
|
||||
ng-model="invoiceInCorrection.correctedFk"
|
||||
url="InvoiceIns"
|
||||
where="{supplierFk: $ctrl.invoiceIn.supplierFk, id: {neq: $ctrl.invoiceIn.id}}"
|
||||
show-field="supplierRef"
|
||||
value-field="id"
|
||||
rule>
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one vn-id="type"
|
||||
label="Type"
|
||||
ng-model="invoiceInCorrection.cplusRectificationTypeFk"
|
||||
url="CplusRectificationTypes"
|
||||
show-field="description"
|
||||
value-field="id"
|
||||
rule>
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one vn-id="class"
|
||||
label="Class"
|
||||
ng-model="invoiceInCorrection.cplusInvoiceType477Fk"
|
||||
url="CplusInvoiceType477s"
|
||||
show-field="description"
|
||||
value-field="id"
|
||||
rule>
|
||||
</vn-autocomplete>
|
||||
<vn-autocomplete vn-one vn-id="reason"
|
||||
label="Reason"
|
||||
ng-model="invoiceInCorrection.invoiceCorrectionTypeFk"
|
||||
url="InvoiceCorrectionTypes"
|
||||
show-field="description"
|
||||
value-field="id"
|
||||
rule>
|
||||
</vn-autocomplete>
|
||||
<vn-none>
|
||||
<vn-icon-button
|
||||
vn-tooltip="Remove correction"
|
||||
icon="delete"
|
||||
ng-click="model.remove($index)"
|
||||
tabindex="-1">
|
||||
</vn-icon-button>
|
||||
</vn-none>
|
||||
</vn-horizontal>
|
||||
<vn-one>
|
||||
<vn-icon-button
|
||||
ng-if="$ctrl.corrections.length == 0"
|
||||
vn-bind="+"
|
||||
vn-tooltip="Add correction"
|
||||
icon="add_circle"
|
||||
ng-click="$ctrl.add()">
|
||||
</vn-icon-button>
|
||||
</vn-one>
|
||||
</vn-card>
|
||||
<vn-button-bar>
|
||||
<vn-submit
|
||||
disabled="!watcher.dataChanged()"
|
||||
label="Save">
|
||||
</vn-submit>
|
||||
</vn-button-bar>
|
||||
</form>
|
|
@ -0,0 +1,34 @@
|
|||
import ngModule from '../module';
|
||||
import Section from 'salix/components/section';
|
||||
|
||||
class Controller extends Section {
|
||||
constructor($element, $) {
|
||||
super($element, $);
|
||||
}
|
||||
|
||||
add() {
|
||||
this.$.model.insert({
|
||||
correctingFk: this.$params.id
|
||||
});
|
||||
}
|
||||
|
||||
onSubmit() {
|
||||
this.$.watcher.check();
|
||||
this.$.model.save().then(() => {
|
||||
this.$.watcher.notifySaved();
|
||||
this.$.watcher.updateOriginalData();
|
||||
this.card.reload();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnInvoiceInCorrection', {
|
||||
template: require('./index.html'),
|
||||
controller: Controller,
|
||||
require: {
|
||||
card: '^vnInvoiceInCard'
|
||||
},
|
||||
bindings: {
|
||||
invoiceIn: '<'
|
||||
}
|
||||
});
|
|
@ -0,0 +1,46 @@
|
|||
import './index.js';
|
||||
import watcher from 'core/mocks/watcher';
|
||||
import crudModel from 'core/mocks/crud-model';
|
||||
|
||||
describe('InvoiceIn', () => {
|
||||
describe('Component correction', () => {
|
||||
let controller;
|
||||
let $scope;
|
||||
let vnApp;
|
||||
|
||||
beforeEach(ngModule('invoiceIn'));
|
||||
|
||||
beforeEach(inject(($componentController, $rootScope, _vnApp_,) => {
|
||||
vnApp = _vnApp_;
|
||||
jest.spyOn(vnApp, 'showError');
|
||||
$scope = $rootScope.$new();
|
||||
$scope.model = crudModel;
|
||||
$scope.watcher = watcher;
|
||||
|
||||
const $element = angular.element('<vn-invoice-in-correction></vn-invoice-in-correction>');
|
||||
controller = $componentController('vnInvoiceInCorrection', {$element, $scope});
|
||||
controller.$.model = crudModel;
|
||||
controller.invoiceIn = {id: 1};
|
||||
}));
|
||||
|
||||
describe('onSubmit()', () => {
|
||||
it('should make HTTP POST request to save correction values', () => {
|
||||
controller.card = {reload: () => {}};
|
||||
jest.spyOn($scope.watcher, 'check');
|
||||
jest.spyOn($scope.watcher, 'notifySaved');
|
||||
jest.spyOn($scope.watcher, 'updateOriginalData');
|
||||
jest.spyOn(controller.card, 'reload');
|
||||
jest.spyOn($scope.model, 'save');
|
||||
|
||||
controller.onSubmit();
|
||||
|
||||
expect($scope.model.save).toHaveBeenCalledWith();
|
||||
expect($scope.watcher.updateOriginalData).toHaveBeenCalledWith();
|
||||
expect($scope.watcher.check).toHaveBeenCalledWith();
|
||||
expect($scope.watcher.notifySaved).toHaveBeenCalledWith();
|
||||
expect(controller.card.reload).toHaveBeenCalledWith();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
@ -61,21 +61,31 @@
|
|||
</div>
|
||||
<div class="quicklinks">
|
||||
<div ng-transclude="btnOne">
|
||||
<vn-quick-link tooltip="Supplier" state="['supplier.card.summary', {id: $ctrl.invoiceIn.supplier.id}]"
|
||||
icon="icon-supplier">
|
||||
</vn-quick-link>
|
||||
</div>
|
||||
<div ng-transclude="btnTwo">
|
||||
<vn-quick-link tooltip="Entries list" state="['entry.index', {q: $ctrl.entryFilter}]"
|
||||
icon="icon-entry">
|
||||
</vn-quick-link>
|
||||
</div>
|
||||
<div ng-transclude="btnThree">
|
||||
<div ng-transclude="btnTwo">
|
||||
<vn-quick-link tooltip="Invoice list" state="['invoiceIn.index', {q: $ctrl.invoiceInFilter}]"
|
||||
icon="icon-invoice-in">
|
||||
</vn-quick-link>
|
||||
</div>
|
||||
|
||||
<div ng-transclude="btnThree">
|
||||
<vn-quick-link
|
||||
ng-if="$ctrl.invoiceIn.invoiceInCorrecting"
|
||||
tooltip="Corrected invoice"
|
||||
state="['invoiceIn.card.summary', {id: $ctrl.invoiceIn.invoiceInCorrecting.correctedFk}]"
|
||||
icon="link">
|
||||
</vn-quick-link>
|
||||
</div>
|
||||
<div ng-transclude="btnFour">
|
||||
<vn-quick-link
|
||||
ng-if="$ctrl.invoiceIn.invoiceInCorrected"
|
||||
tooltip="Origin invoice"
|
||||
state="['invoiceIn.card.summary', {id: $ctrl.invoiceIn.invoiceInCorrected.correctingFk}]"
|
||||
icon="link">
|
||||
</vn-quick-link>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</slot-body>
|
||||
|
|
|
@ -114,6 +114,24 @@ class Controller extends Descriptor {
|
|||
isAgricultural() {
|
||||
return this.invoiceIn.supplier.sageWithholdingFk == this.config[0].sageWithholdingFk;
|
||||
}
|
||||
|
||||
get invoiceInCorrection() {
|
||||
if (this.invoiceIn) {
|
||||
if (this.invoiceIn.invoiceInCorrecting) {
|
||||
return {
|
||||
tooltip: this.$t('Corrected invoice'),
|
||||
id: this.invoiceIn.invoiceInCorrecting.correctedFk
|
||||
};
|
||||
} else if (this.invoiceIn.invoiceInCorrected) {
|
||||
return {
|
||||
tooltip: this.$t('Origin invoice'),
|
||||
id: this.invoiceIn.invoiceInCorrected.correctingFk
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
ngModule.vnComponent('vnInvoiceInDescriptor', {
|
||||
|
|
|
@ -15,3 +15,5 @@ import './create';
|
|||
import './log';
|
||||
import './serial';
|
||||
import './serial-search-panel';
|
||||
import './correction';
|
||||
|
||||
|
|
|
@ -25,3 +25,8 @@ Send agricultural receipt as PDF: Enviar recibo agrícola como PDF
|
|||
New InvoiceIn: Nueva Factura
|
||||
Days ago: Últimos días
|
||||
Negative bases: Bases negativas
|
||||
Correction: Rectificativa
|
||||
Add correction: Añadir rectificativa
|
||||
Remove correction: Borrar rectificativa
|
||||
Origin invoice: Factura origen
|
||||
Corrected invoice: Factura rectificativa
|
||||
|
|
|
@ -29,6 +29,10 @@
|
|||
"state": "invoiceIn.card.intrastat",
|
||||
"icon": "icon-lines"
|
||||
},
|
||||
{
|
||||
"state": "invoiceIn.card.correction",
|
||||
"icon": "link"
|
||||
},
|
||||
{
|
||||
"state": "invoiceIn.card.log",
|
||||
"icon": "history"
|
||||
|
@ -110,6 +114,16 @@
|
|||
},
|
||||
"acl": ["administrative"]
|
||||
},
|
||||
{
|
||||
"url": "/correction",
|
||||
"state": "invoiceIn.card.correction",
|
||||
"component": "vn-invoice-in-correction",
|
||||
"description": "Correction",
|
||||
"params": {
|
||||
"invoice-in": "$ctrl.invoiceIn"
|
||||
},
|
||||
"acl": ["administrative"]
|
||||
},
|
||||
{
|
||||
"url": "/dueDay",
|
||||
"state": "invoiceIn.card.dueDay",
|
||||
|
|
|
@ -151,7 +151,45 @@
|
|||
</vn-table>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
<vn-horizontal>
|
||||
<vn-one ng-if="$ctrl.summary.invoiceInCorrecting">
|
||||
<h4>
|
||||
<a
|
||||
ui-sref="invoiceIn.card.correction({id:$ctrl.invoiceIn.id})"
|
||||
target="_self">
|
||||
<span translate vn-tooltip="Go to">Correction</span>
|
||||
</a>
|
||||
</h4>
|
||||
<vn-table model="model">
|
||||
<vn-thead>
|
||||
<vn-tr>
|
||||
<vn-th>Origin invoice</vn-th>
|
||||
<vn-th>Type</vn-th>
|
||||
<vn-th>Class</vn-th>
|
||||
<vn-th>Reason</vn-th>
|
||||
</vn-tr>
|
||||
</vn-thead>
|
||||
<vn-tbody>
|
||||
<vn-tr>
|
||||
<vn-td>
|
||||
<span
|
||||
vn-click-stop="invoiceInDescriptor.show($event, $ctrl.summary.invoiceInCorrecting.correctedFk)"
|
||||
class="link">
|
||||
{{$ctrl.summary.invoiceInCorrecting.corrected.supplierRef}}
|
||||
</span>
|
||||
</vn-td>
|
||||
<vn-td>{{$ctrl.summary.invoiceInCorrecting.cplusRectificationType.description}}</vn-td>
|
||||
<vn-td>{{$ctrl.summary.invoiceInCorrecting.cplusInvoiceType477.description}}</vn-td>
|
||||
<vn-td>{{$ctrl.summary.invoiceInCorrecting.invoiceCorrectionType.description}}</vn-td>
|
||||
</vn-tr>
|
||||
</vn-tbody>
|
||||
</vn-table>
|
||||
</vn-one>
|
||||
</vn-horizontal>
|
||||
</vn-card>
|
||||
<vn-supplier-descriptor-popover
|
||||
vn-id="supplierDescriptor">
|
||||
</vn-supplier-descriptor-popover>
|
||||
<vn-invoice-in-descriptor-popover
|
||||
vn-id="invoiceInDescriptor">
|
||||
</vn-invoice-in-descriptor-popover>
|
||||
|
|
Loading…
Reference in New Issue