Merge branch 'dev' into 7880-hedera.order_confirmWithUserTranslations
gitea/salix/pipeline/pr-dev This commit looks good Details

This commit is contained in:
Ivan Mas 2024-12-18 11:17:14 +00:00
commit ab5cf0f497
30 changed files with 508 additions and 51 deletions

View File

@ -1922,7 +1922,7 @@ INSERT INTO `vn`.`claimDestination`(`id`, `description`, `addressFk`)
INSERT INTO `vn`.`claimDevelopment`(`id`, `claimFk`, `claimResponsibleFk`, `workerFk`, `claimReasonFk`, `claimResultFk`, `claimRedeliveryFk`, `claimDestinationFk`)
VALUES
(1, 1, 1, 21, 1, 1, 2, 5),
(1, 1, 1, 21, 7, 1, 2, 5),
(2, 1, 2, 21, 7, 2, 2, 5),
(3, 2, 7, 21, 9, 3, 2, 5),
(4, 3, 7, 21, 15, 8, 2, 5),
@ -4038,6 +4038,11 @@ INSERT IGNORE INTO vn.saySimpleConfig (url, defaultChannel)
INSERT INTO vn.workerIrpf (workerFk,spouseNif, geographicMobilityDate)
VALUES (1106,'26493101E','2019-09-20');
INSERT INTO vn.referenceRate (currencyFk, dated, value)
VALUES (2, '2000-12-01', 1.0495),
(2, '2001-01-01', 1.0531),
(2, '2001-02-01', 7.6347);
INSERT IGNORE INTO vn.osrmConfig (id,url,tolerance)
VALUES (1,'https://router.project-osrm.org', 0.002);

View File

@ -4,10 +4,10 @@ BEGIN
/**
* Traslada la info de contabilidad relacionada con las facturas recibidas
*
* @vInvoiceInFk Factura recibida
* @vXDiarioFk Id tabla XDiario
* @param vInvoiceInFk Factura recibida
* @param vXDiarioFk Id tabla XDiario
*/
DECLARE vInvoiceInOriginalFk INT;
DECLARE vInvoiceInOriginalFk INT;
DECLARE vDone BOOL DEFAULT FALSE;
DECLARE vBase DOUBLE;
DECLARE vVat DOUBLE;
@ -205,9 +205,9 @@ BEGIN
WHERE correctingFk = vInvoiceInFk;
IF vInvoiceInOriginalFk THEN
UPDATE movContaIVA mci
JOIN vn.invoiceInRefund iir ON iir.invoiceInRefundFk = vInvoiceInFk
JOIN vn.invoiceInCorrection iic ON iic.correctingFk = vInvoiceInFk
JOIN vn.siiTypeInvoiceIn st ON st.id = iic.siiTypeInvoiceInFk
JOIN (SELECT issued,
SUM(sub.taxableBase) taxableBase,
SUM(ROUND((sub.taxableBase * sub.PorcentajeIva) / 100 , 2)) vat
@ -216,7 +216,7 @@ BEGIN
ti.PorcentajeIva
FROM vn.invoiceIn i
JOIN vn.invoiceInTax iit ON iit.invoiceInFk = i.id
JOIN sage.TiposIva ti ON ti.CodigoIva = iit.taxTypeSageFk
JOIN TiposIva ti ON ti.CodigoIva = iit.taxTypeSageFk
WHERE i.id = vInvoiceInOriginalFk
GROUP BY ti.CodigoIva)sub
)invoiceInOriginal
@ -229,7 +229,6 @@ BEGIN
mci.CuotaIvaOriginal = invoiceInOriginal.vat,
mci.ClaveOperacionFactura = co.ClaveOperacionFactura_
WHERE mci.id = vXDiarioFk;
END IF;
END$$
DELIMITER ;

View File

@ -169,6 +169,7 @@ BEGIN
UPDATE movContaIVA mci
JOIN vn.invoiceOut i ON i.id = vInvoiceOutCorrectedFk
JOIN vn.invoiceCorrection ic ON ic.correctedFk = vInvoiceOutCorrectedFk
JOIN vn.siiTypeInvoiceOut st ON st.id = ic.siiTypeInvoiceOutFk
JOIN (SELECT SUM(IF(IFNULL(e.vatFk, TRUE), iot.taxableBase, 0)) taxableBase,
SUM(IF(IFNULL(e.vatFk, TRUE), iot.vat, 0)) vat,
SUM(IF(IFNULL(e.vatFk, TRUE), 0, iot.vat)) equ
@ -177,8 +178,8 @@ BEGIN
WHERE iot.invoiceOutFk = vInvoiceOutCorrectedFk
) tax
JOIN ClavesOperacion co ON co.Descripcion = 'Factura rectificativa'
SET mci.TipoRectificativa = 2,
mci.ClaseAbonoRectificativas = 1,
SET mci.TipoRectificativa = ic.cplusRectificationTypeFk,
mci.ClaseAbonoRectificativas = REGEXP_REPLACE(st.`code`, '[^0-9]', ''),
mci.FechaFacturaOriginal = i.issued,
mci.FechaOperacion = i.issued,
mci.BaseImponibleOriginal = tax.taxableBase,

View File

@ -43,7 +43,7 @@ BEGIN
ii.cplusTaxBreakFk,
ii.cplusSubjectOpFk,
ii.siiTypeInvoiceInFk,
ii.cplusRectificationTypeFk,
ic.cplusRectificationTypeFk,
ii.booked,
IFNULL(a.isUeeMember, c.isUeeMember) isUeeMember,
(c.id = cc.id) isSameCountry,
@ -66,6 +66,7 @@ BEGIN
e.name expenseName
FROM invoiceIn ii
JOIN supplier s ON s.id = ii.supplierFk
LEFT JOIN invoiceInCorrection ic ON ic.correctingFk = ii.id
LEFT JOIN province p ON p.id = s.provinceFk
LEFT JOIN autonomy a ON a.id = p.autonomyFk
JOIN country c ON c.id = s.countryFk

View File

@ -52,7 +52,8 @@ BEGIN
IFNULL(dest.nickname, origin.nickname) nickname,
dest.landed,
dest.preparation,
origin.departmentFk
origin.departmentFk,
origin.saleClonedFk
FROM (
SELECT s.ticketFk,
c.salesPersonFk workerFk,
@ -73,11 +74,13 @@ BEGIN
t.warehouseFk,
t.companyFk,
t.agencyModeFk,
wd.departmentFk
wd.departmentFk,
sc.saleClonedFk
FROM ticket t
JOIN client c ON c.id = t.clientFk
JOIN workerDepartment wd ON wd.workerFk = c.salesPersonFk
JOIN sale s ON s.ticketFk = t.id
LEFT JOIN saleCloned sc ON sc.saleClonedFk = s.id
JOIN saleVolume sv ON sv.saleFk = s.id
JOIN item i ON i.id = s.itemFk
JOIN ticketState ts ON ts.ticketFk = t.id

View File

@ -3,24 +3,30 @@ CREATE OR REPLACE DEFINER=`vn`@`localhost` TRIGGER `vn`.`invoiceIn_afterUpdate`
AFTER UPDATE ON `invoiceIn`
FOR EACH ROW
BEGIN
IF NEW.issued != OLD.issued
OR NEW.currencyFk != OLD.currencyFk THEN
DECLARE vIsEuro BOOL;
SELECT `code` = 'EUR' INTO vIsEuro
FROM currency
WHERE id = NEW.currencyFk;
IF (NOT NEW.issued <=> OLD.issued
OR NEW.currencyFk <> OLD.currencyFk) THEN
UPDATE invoiceInTax iit
JOIN invoiceIn ii ON ii.id = iit.invoiceInFk
LEFT JOIN referenceRate rr ON rr.dated = ii.issued
AND rr.currencyFk = ii.currencyFk
SET iit.taxableBase = IF(iit.foreignValue IS NULL, iit.taxableBase, iit.foreignValue / rr.value)
SET iit.taxableBase = IF(vIsEuro, iit.taxableBase, iit.foreignValue / rr.value),
iit.foreignValue = IF(vIsEuro, NULL, iit.foreignValue)
WHERE ii.id = NEW.id;
UPDATE invoiceInDueDay iidd
JOIN invoiceIn ii ON ii.id = iidd.invoiceInFk
LEFT JOIN referenceRate rr ON rr.dated = ii.issued
AND rr.currencyFk = ii.currencyFk
SET iidd.amount = IF(iidd.foreignValue IS NULL, iidd.amount, iidd.foreignValue / rr.value)
SET iidd.amount = IF(vIsEuro, iidd.amount, iidd.foreignValue / rr.value),
iidd.foreignValue = IF(vIsEuro, NULL, iidd.foreignValue)
WHERE ii.id = NEW.id;
END IF;
END$$
DELIMITER ;

View File

@ -0,0 +1,48 @@
USE vn;
DROP TRIGGER IF EXISTS invoiceIn_beforeUpdate;
UPDATE invoiceIn
SET cplusRectificationTypeFk = NULL
WHERE cplusRectificationTypeFk = 1;
DELETE IGNORE FROM cplusRectificationType WHERE id = 1;
UPDATE cplusRectificationType
SET id = 1
WHERE id = 3;
DELIMITER $$
CREATE OR REPLACE DEFINER=`vn`@`localhost` TRIGGER `vn`.`invoiceIn_beforeUpdate`
BEFORE UPDATE ON `invoiceIn`
FOR EACH ROW
BEGIN
DECLARE vWithholdingSageFk INT;
IF NOT (NEW.supplierRef <=> OLD.supplierRef) AND NOT util.checkPrintableChars(NEW.supplierRef) THEN
CALL util.throw('The invoiceIn reference contains invalid characters');
END IF;
SET NEW.editorFk = account.myUser_getId();
IF (SELECT COUNT(*) FROM invoiceIn
WHERE supplierRef = NEW.supplierRef
AND supplierFk = NEW.supplierFk
AND YEAR(issued) = YEAR(NEW.issued)
AND id <> NEW.id
) THEN
CALL util.throw('reference duplicated');
END IF;
IF NEW.supplierFk != OLD.supplierFk THEN
CALL supplier_checkIsActive(NEW.supplierFk);
SELECT withholdingSageFk INTO vWithholdingSageFk
FROM supplier
WHERE id = NEW.supplierFk;
SET NEW.withholdingSageFk = vWithholdingSageFk;
END IF;
END$$
DELIMITER ;

View File

@ -0,0 +1,23 @@
INSERT INTO salix.ACL (model, property, accessType, permission, principalType, principalId)
VALUES('SiiTypeInvoiceIn', 'find', 'READ', 'ALLOW', 'ROLE', 'salesPerson');
DROP TABLE IF EXISTS vn.invoiceInCorrection;
CREATE TABLE `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,
`siiTypeInvoiceInFk` 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_siiTypeInvoiceIn` (`siiTypeInvoiceInFk`),
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_cplusRectificationTypeFk` FOREIGN KEY (`cplusRectificationTypeFk`) REFERENCES `cplusRectificationType` (`id`) ON UPDATE CASCADE,
CONSTRAINT `invoiceInCorrection_invoiceCorrectionTypeFk` FOREIGN KEY (`invoiceCorrectionTypeFk`) REFERENCES `invoiceCorrectionType` (`id`) ON UPDATE CASCADE,
CONSTRAINT `invoiceInCorrection_siiTypeInvoiceIn` FOREIGN KEY (`siiTypeInvoiceInFk`) REFERENCES `siiTypeInvoiceIn` (`id`) ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8mb3_unicode_ci;

View File

@ -80,6 +80,12 @@ module.exports = Self => {
description: 'The claimResponsible id',
http: {source: 'query'}
},
{
arg: 'zoneFk',
type: 'string',
description: 'The zone name',
http: {source: 'query'}
},
{
arg: 'myTeam',
type: 'boolean',
@ -174,6 +180,8 @@ module.exports = Self => {
to.setHours(23, 59, 59, 999);
return {'cl.created': {between: [value, to]}};
case 'zoneFk':
return {'t.zoneFk': value};
case 'myTeam':
if (value)
return {'cl.workerFk': {inq: teamMembersId}};
@ -195,11 +203,15 @@ module.exports = Self => {
u.name AS workerName,
cs.code stateCode,
cs.description stateDescription,
cl.created
cl.created,
z.name zoneName,
z.id zoneId
FROM claim cl
LEFT JOIN client c ON c.id = cl.clientFk
LEFT JOIN account.user u ON u.id = cl.workerFk
LEFT JOIN claimState cs ON cs.id = cl.claimStateFk`
LEFT JOIN claimState cs ON cs.id = cl.claimStateFk
LEFT JOIN ticket t ON t.id = cl.ticketFk
LEFT JOIN zone z ON z.id = t.zoneFk`
);
stmt.merge(conn.makeSuffix(filter));

View File

@ -44,7 +44,7 @@ module.exports = Self => {
correctingFk: clone.id,
correctedFk: id,
cplusRectificationTypeFk: invoiceType,
siiTypeInvoiceOutFk: invoiceClass,
siiTypeInvoiceInFk: invoiceClass,
invoiceCorrectionTypeFk: invoiceReason
}, myOptions);

View File

@ -91,6 +91,10 @@ module.exports = Self => {
{
arg: 'supplierActivityFk',
type: 'string',
},
{
arg: 'companyFk',
type: 'number',
}
],
returns: {
@ -161,8 +165,8 @@ module.exports = Self => {
: {'ii.id': {nin: correcteds.map(x => x.correctingFk)}};
case 'correctedFk':
return {'ii.id': {inq: correctings.map(x => x.correctingFk)}};
case 'supplierActivityFk':
return {'s.supplierActivityFk': value};
case 'companyFk':
return {'ii.companyFk': value};
}
});
@ -184,7 +188,9 @@ module.exports = Self => {
s.name supplierName,
s.account,
SUM(iid.amount) amount,
sub.code awbCode
sub.code awbCode,
c.code,
MIN(iid.dueDated) dueDated
FROM invoiceIn ii
JOIN supplier s ON s.id = ii.supplierFk
LEFT JOIN invoiceInDueDay iid ON iid.invoiceInFk = ii.id
@ -199,7 +205,8 @@ module.exports = Self => {
GROUP BY de.duaFk
) sub ON sub.duaFk = d.id
LEFT JOIN company co ON co.id = ii.companyFk
LEFT JOIN dms dm ON dm.id = ii.docFk`
LEFT JOIN dms dm ON dm.id = ii.docFk
JOIN company c ON c.id = ii.companyFk`,
);
const sqlWhere = conn.makeWhere(filter.where);

View File

@ -15,11 +15,11 @@ describe('invoiceIn corrective()', () => {
await tx.rollback();
});
it('La función corrective debería devolver un id cuando se ejecuta correctamente', async() => {
it('should return an id when executed correctly', async() => {
const originalId = 1;
const invoiceReason = 3;
const invoiceType = 2;
const invoiceClass = 1;
const invoiceClass = 8;
const cloneId = await models.InvoiceIn.corrective(ctx,
originalId, invoiceReason, invoiceType, invoiceClass, options);
@ -30,7 +30,7 @@ describe('invoiceIn corrective()', () => {
}, options);
expect(correction.cplusRectificationTypeFk).toEqual(invoiceType);
expect(correction.siiTypeInvoiceOutFk).toEqual(invoiceClass);
expect(correction.siiTypeInvoiceInFk).toEqual(invoiceClass);
expect(correction.invoiceCorrectionTypeFk).toEqual(invoiceReason);
});
});

View File

@ -166,4 +166,21 @@ describe('InvoiceIn filter()', () => {
throw e;
}
});
it('should return the invoice in matching companyFk', async() => {
const tx = await models.InvoiceIn.beginTransaction({});
const options = {transaction: tx};
try {
const company = await models.Company.findOne({}, options);
const invoicesByCompany = await models.InvoiceIn.find({where: {companyFk: company.id}}, options);
const filteredInvoices = await models.InvoiceIn.filter({args: {companyFk: company.id}}, {}, options);
expect(filteredInvoices.length).toEqual(invoicesByCompany.length);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -0,0 +1,63 @@
const models = require('vn-loopback/server/server').models;
describe('invoiceIn', () => {
let options;
let tx;
const invoiceId = 1;
const supplierId = 791;
const currencyId = 1;
const companyId = 442;
beforeEach(async() => {
tx = await models.InvoiceIn.beginTransaction({});
options = {transaction: tx};
});
afterEach(async() => {
await tx.rollback();
});
it('should allow insert for new instance', async() => {
const newInvoice = {
supplierFk: supplierId,
issued: Date.vnNew(),
operated: Date.vnNew(),
currencyFk: currencyId,
companyFk: companyId,
isBooked: false
};
const createdInvoice = await models.InvoiceIn.create(newInvoice, options);
expect(createdInvoice).toBeDefined();
expect(createdInvoice.id).toBeDefined();
});
it('should throw an error if trying to update a booked invoice', async() => {
const invoice = await models.InvoiceIn.findById(invoiceId, null, options);
await invoice.updateAttribute('isBooked', true, options);
let error;
try {
await invoice.updateAttribute('supplierFk', supplierId, options);
} catch (err) {
error = err;
}
expect(error.message).toBe('InvoiceIn is already booked');
});
it('should throw an error if trying to delete a booked invoice', async() => {
const invoice = await models.InvoiceIn.findById(invoiceId, null, options);
await invoice.updateAttribute('isBooked', true, options);
let error;
try {
await models.InvoiceIn.deleteById(invoiceId, options);
} catch (err) {
error = err;
}
expect(error.message).toBe('InvoiceIn is already booked');
});
});

View File

@ -0,0 +1,74 @@
const models = require('vn-loopback/server/server').models;
describe('invoiceInTax', () => {
let options;
let tx;
const invoiceInId = 1;
const invoiceInTaxId = 1;
beforeEach(async() => {
tx = await models.InvoiceInTax.beginTransaction({});
options = {transaction: tx};
});
afterEach(async() => {
await tx.rollback();
});
it('should throw an error if trying to save a tax from a booked invoice', async() => {
const invoiceIn = await models.InvoiceIn.findById(invoiceInId, null, options);
await invoiceIn.updateAttributes({isBooked: true}, options);
const invoiceInTax = await models.InvoiceInTax.findById(invoiceInTaxId, null, options);
let error;
try {
await invoiceInTax.updateAttribute('taxableBase', 100, options);
} catch (err) {
error = err;
}
expect(error.message).toBe('InvoiceIn is already booked');
});
it('should allow save if the invoice is not booked', async() => {
const invoiceIn = await models.InvoiceIn.findById(invoiceInId, null, options);
await invoiceIn.updateAttribute('isBooked', false, options);
const invoiceInTax = await models.InvoiceInTax.findById(invoiceInTaxId, null, options);
await invoiceInTax.updateAttribute('taxableBase', 100, options);
const updatedInvoiceInTax = await models.InvoiceInTax.findById(invoiceInTaxId, null, options);
expect(updatedInvoiceInTax.taxableBase).toBe(100);
});
it('should throw an error if trying to delete a tax from a booked invoice', async() => {
const invoiceIn = await models.InvoiceIn.findById(invoiceInId, null, options);
await invoiceIn.updateAttribute('isBooked', true, options);
let error;
try {
await models.InvoiceInTax.destroyById(invoiceInTaxId, options);
} catch (err) {
error = err;
}
expect(error).toBeDefined();
expect(error.message).toBe('InvoiceIn is already booked');
});
it('should allow delete if the invoice is not booked', async() => {
const invoiceIn = await models.InvoiceIn.findById(invoiceInId, null, options);
await invoiceIn.updateAttribute('isBooked', false, options);
let error;
try {
await models.InvoiceInTax.destroyById(invoiceInTaxId, options);
} catch (err) {
error = err;
}
const deletedInvoiceInTax = await models.InvoiceInTax.findById(invoiceInTaxId, null, options);
expect(error).toBeUndefined();
expect(deletedInvoiceInTax).toBeNull();
});
});

View File

@ -0,0 +1,59 @@
const models = require('vn-loopback/server/server').models;
const invoiceInId = 1;
const supplierId = 791;
describe('invoiceIn updateInvoiceIn()', () => {
const ctx = beforeAll.getCtx();
let options;
let tx;
beforeEach(async() => {
options = {transaction: tx};
tx = await models.Sale.beginTransaction({});
options.transaction = tx;
});
afterEach(async() => {
await tx.rollback();
});
it('should update the invoice', async() => {
const invoiceBefore = await models.InvoiceIn.findById(invoiceInId, null, options);
await update(ctx, options);
const invoiceAfter = await models.InvoiceIn.findById(invoiceInId, null, options);
expect(invoiceAfter.supplierFk).not.toBe(invoiceBefore.supplierFk);
expect(invoiceAfter.supplierFk).toBe(supplierId);
});
it('should not update the invoice if is booked', async() => {
let error;
try {
await models.InvoiceIn.toBook(ctx, invoiceInId, options);
await update(ctx, options);
} catch (e) {
error = e;
}
expect(error.message).toBe('InvoiceIn is already booked');
});
});
async function update(ctx, opts) {
const supplierRef = 'mockRef';
const currencyId = 1;
await models.InvoiceIn.updateInvoiceIn(ctx,
invoiceInId,
supplierId,
supplierRef,
undefined,
undefined,
undefined,
undefined,
undefined,
undefined,
currencyId,
undefined,
undefined,
opts);
}

View File

@ -37,7 +37,13 @@ module.exports = Self => {
{
relation: 'supplier',
scope: {
fields: ['id', 'name']
fields: ['id', 'name', 'isVies', 'countryFk'],
include: [{
relation: 'country',
scope: {
fields: ['id', 'code']
}
}]
}
},
{

View File

@ -52,7 +52,8 @@ module.exports = Self => {
accountingEntries = await models.Xdiario.count({ASIEN: asien}, myOptions);
await models.Xdiario.destroyAll({ASIEN: asien}, myOptions);
await Self.updateAll({id: invoiceInId}, {isBooked: false}, myOptions);
const invoiceIn = await Self.findById(invoiceInId, myOptions);
await invoiceIn.updateAttribute('isBooked', false, myOptions);
} else {
const linkedBookEntry = await models.Xdiario.findOne({
fields: ['ASIEN'],

View File

@ -82,7 +82,7 @@ module.exports = Self => {
try {
const invoiceIn = await Self.findById(id, null, myOptions);
invoiceIn.updateAttributes({supplierFk,
await invoiceIn.updateAttributes({supplierFk,
supplierRef,
issued,
operated,
@ -94,6 +94,7 @@ module.exports = Self => {
companyFk,
withholdingSageFk
}, myOptions);
if (tx) await tx.commit();
return invoiceIn;
} catch (e) {

View File

@ -28,11 +28,10 @@
"model": "InvoiceCorrectionType",
"foreignKey": "invoiceCorrectionTypeFk"
},
"siiTypeInvoiceOut": {
"siiTypeInvoiceIn": {
"type": "belongsTo",
"model": "SiiTypeInvoiceOut",
"foreignKey": "siiTypeInvoiceOutFk"
"model": "SiiTypeInvoiceIn",
"foreignKey": "siiTypeInvoiceInFk"
}
}
}

View File

@ -0,0 +1,18 @@
const UserError = require('vn-loopback/util/user-error');
module.exports = Self => {
Self.observe('before save', async function(ctx) {
if (ctx.isNewInstance) return;
const models = Self.app.models;
const invoiceIn = await models.InvoiceIn.findById(ctx.currentInstance.invoiceInFk, null, ctx.options);
if (invoiceIn.isBooked) throw new UserError('InvoiceIn is already booked');
});
Self.observe('before delete', async function(ctx) {
const models = Self.app.models;
const invoiceInTax = await Self.findById(ctx.where.id, null, ctx.options);
const invoiceIn = await models.InvoiceIn.findById(invoiceInTax.invoiceInFk, null, ctx.options);
if (invoiceIn.isBooked) throw new UserError('InvoiceIn is already booked');
});
};

View File

@ -22,12 +22,11 @@
"type": "number"
},
"expenseFk": {
"type": "number"
"type": "string"
},
"created": {
"type": "date"
}
},
"relations": {
"invoiceIn": {
@ -51,4 +50,4 @@
"foreignKey": "transactionTypeSageFk"
}
}
}
}

View File

@ -19,4 +19,25 @@ module.exports = Self => {
return new UserError(`This invoice has a linked vehicle.`);
return err;
});
Self.observe('before save', async function(ctx) {
if (ctx.isNewInstance) return;
const changes = ctx.data || ctx.instance;
const orgData = ctx.currentInstance;
let isNotEditable = orgData.isBooked || (!orgData.isBooked && changes.isBooked);
if (isNotEditable) {
for (const [key, value] of Object.entries(changes)) {
if (key !== 'isBooked' && value !== orgData[key])
throw new UserError('InvoiceIn is already booked');
}
}
});
Self.observe('before delete', async function(ctx) {
const invoiceIn = await Self.findById(ctx.where.id, null, ctx.options);
if (invoiceIn.isBooked) throw new UserError('InvoiceIn is already booked');
});
};

View File

@ -43,5 +43,8 @@
},
"SiiTypeInvoiceOut": {
"dataSource": "vn"
},
"SiiTypeInvoiceIn": {
"dataSource": "vn"
}
}
}

View File

@ -0,0 +1,22 @@
{
"name": "SiiTypeInvoiceIn",
"base": "VnModel",
"options": {
"mysql": {
"table": "siiTypeInvoiceIn"
}
},
"properties": {
"id": {
"id": true,
"type": "number",
"description": "Identifier"
},
"code": {
"type": "string"
},
"description": {
"type": "string"
}
}
}

View File

@ -17,9 +17,6 @@
},
"description": {
"type": "string"
},
"code": {
"type": "string"
}
}
}
}

View File

@ -55,6 +55,11 @@ module.exports = Self => {
type: 'number',
description: 'Department identifier'
},
{
arg: 'onlyWithDestination',
type: 'Boolean',
description: 'True when only tickets with destination are returned'
},
{
arg: 'filter',
type: 'object',
@ -103,6 +108,8 @@ module.exports = Self => {
return {'f.isFullMovable': value};
case 'departmentFk':
return {'f.departmentFk': value};
case 'onlyWithDestination':
return {'f.id': value ? {neq: null} : null};
}
});

View File

@ -8,6 +8,7 @@ describe('TicketFuture getTicketsAdvance()', () => {
tomorrow.setDate(today.getDate() + 1);
const salesDeptId = 43;
const spain1DeptId = 95;
const warehouseId = 1;
beforeAll.mockLoopBackContext();
it('should return the tickets passing the required data', async() => {
@ -19,7 +20,7 @@ describe('TicketFuture getTicketsAdvance()', () => {
const args = {
dateFuture: tomorrow,
dateToAdvance: today,
warehouseFk: 1,
warehouseFk: warehouseId,
};
ctx.args = args;
@ -42,7 +43,7 @@ describe('TicketFuture getTicketsAdvance()', () => {
const args = {
dateFuture: tomorrow,
dateToAdvance: today,
warehouseFk: 1,
warehouseFk: warehouseId,
isFullMovable: true
};
@ -67,7 +68,7 @@ describe('TicketFuture getTicketsAdvance()', () => {
const args = {
dateFuture: tomorrow,
dateToAdvance: today,
warehouseFk: 1,
warehouseFk: warehouseId,
isFullMovable: false
};
@ -92,7 +93,7 @@ describe('TicketFuture getTicketsAdvance()', () => {
const args = {
dateFuture: tomorrow,
dateToAdvance: today,
warehouseFk: 1,
warehouseFk: warehouseId,
ipt: 'V'
};
@ -117,7 +118,7 @@ describe('TicketFuture getTicketsAdvance()', () => {
const args = {
dateFuture: tomorrow,
dateToAdvance: today,
warehouseFk: 1,
warehouseFk: warehouseId,
tfIpt: 'V'
};
@ -141,7 +142,7 @@ describe('TicketFuture getTicketsAdvance()', () => {
ctx.args = {
dateFuture: tomorrow,
dateToAdvance: today,
warehouseFk: 1,
warehouseFk: warehouseId,
};
await models.Ticket.updateAll({id: {inq: [12, 31]}}, {clientFk: 1}, options);
@ -167,4 +168,56 @@ describe('TicketFuture getTicketsAdvance()', () => {
throw e;
}
});
it('should return the tickets with only destination', async() => {
const tx = await models.Ticket.beginTransaction({});
try {
const options = {transaction: tx};
const args = {
dateFuture: today,
dateToAdvance: today.setHours(23, 59, 59, 999),
warehouseFk: warehouseId,
};
ctx.args = args;
const allTickets = await models.Ticket.getTicketsAdvance(ctx, options);
ctx.args.onlyWithDestination = true;
const withDestinationTickets = await models.Ticket.getTicketsAdvance(ctx, options);
expect(allTickets.filter(ticket => ticket.id).length).toBe(withDestinationTickets.length);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
it('should return the tickets without only destination', async() => {
const tx = await models.Ticket.beginTransaction({});
try {
const options = {transaction: tx};
const args = {
dateFuture: today,
dateToAdvance: today.setHours(23, 59, 59, 999),
warehouseFk: warehouseId,
};
ctx.args = args;
const allTickets = await models.Ticket.getTicketsAdvance(ctx, options);
ctx.args.onlyWithDestination = false;
const withoutDestinationTickets = await models.Ticket.getTicketsAdvance(ctx, options);
expect(allTickets.filter(ticket => !ticket.id).length).toBe(withoutDestinationTickets.length);
await tx.rollback();
} catch (e) {
await tx.rollback();
throw e;
}
});
});

View File

@ -83,6 +83,14 @@ module.exports = Self => {
arg: 'daysOnward',
type: 'number',
description: 'The days onward'
}, {
arg: 'shipped',
type: 'date',
description: 'The shipped date'
}, {
arg: 'landed',
type: 'date',
description: 'The landed date'
}
],
returns: {
@ -108,6 +116,10 @@ module.exports = Self => {
: {'t.ref': {like: `%${value}%`}};
case 'ref':
return {'t.ref': {like: `%${value}%`}};
case 'shipped':
return {'t.shipped': value};
case 'landed':
return {'t.landed': value};
case 'shippedFrom':
return {'t.shipped': {gte: value}};
case 'shippedTo':

View File

@ -1,6 +1,6 @@
{
"name": "salix-back",
"version": "24.52.0",
"version": "25.02.0",
"author": "Verdnatura Levante SL",
"description": "Salix backend",
"license": "GPL-3.0",