#5878 - FiscalData validations #1851

Merged
carlossa merged 58 commits from 5858-fiscalData-validations into dev 2024-02-28 13:53:34 +00:00
12 changed files with 317 additions and 26 deletions
Showing only changes of commit ed37902291 - Show all commits

View File

@ -203,11 +203,19 @@
"keepPrice": "keepPrice",
"Cannot past travels with entries": "Cannot past travels with entries",
"It was not able to remove the next expeditions:": "It was not able to remove the next expeditions: {{expeditions}}",
<<<<<<< HEAD
=======
"Try again": "Try again",
>>>>>>> 5918c14d41259e9989b63c8a36f0e23612cf5d69
"Incorrect pin": "Incorrect pin.",
"The notification subscription of this worker cant be modified": "The notification subscription of this worker cant be modified",
"Name should be uppercase": "Name should be uppercase",
"You cannot update these fields": "You cannot update these fields",
<<<<<<< HEAD
"CountryFK cannot be empty": "Country cannot be empty",
"You are not allowed to modify the alias": "You are not allowed to modify the alias",
"You already have the mailAlias": "You already have the mailAlias"
=======
"CountryFK cannot be empty": "Country cannot be empty"
>>>>>>> 5918c14d41259e9989b63c8a36f0e23612cf5d69
}

View File

@ -1,4 +1,8 @@
{
<<<<<<< HEAD
=======
"postalcode": "Código postal",
>>>>>>> 5918c14d41259e9989b63c8a36f0e23612cf5d69
"Phone format is invalid": "El formato del teléfono no es correcto",
"You are not allowed to change the credit": "No tienes privilegios para modificar el crédito",
"Unable to mark the equivalence surcharge": "No se puede marcar el recargo de equivalencia",
@ -139,7 +143,11 @@
"Claim state has changed to": "Se ha cambiado el estado de la reclamación [({{claimId}})]({{{claimUrl}}}) del cliente *{{clientName}}* a *{{newState}}*",
"Client checked as validated despite of duplication": "Cliente comprobado a pesar de que existe el cliente id {{clientId}}",
"ORDER_ROW_UNAVAILABLE": "No hay disponibilidad de este producto",
<<<<<<< HEAD
"Distance must be lesser than 4000": "La distancia debe ser inferior a 4000",
=======
"Distance must be lesser than 1000": "La distancia debe ser inferior a 1000",
>>>>>>> 5918c14d41259e9989b63c8a36f0e23612cf5d69
"This ticket is deleted": "Este ticket está eliminado",
"Unable to clone this travel": "No ha sido posible clonar este travel",
"This thermograph id already exists": "La id del termógrafo ya existe",
@ -333,16 +341,28 @@
"It was not able to remove the next expeditions:": "No se pudo eliminar las siguientes expediciones: {{expeditions}}",
"This claim has been updated": "La reclamación con Id: {{claimId}}, ha sido actualizada",
"This user does not have an assigned tablet": "Este usuario no tiene tablet asignada",
<<<<<<< HEAD
"Incorrect pin": "Pin incorrecto",
"You already have the mailAlias": "Ya tienes este alias de correo",
"The alias cant be modified": "Este alias de correo no puede ser modificado",
=======
"Field are invalid": "El campo '{{tag}}' no es válido",
"Incorrect pin": "Pin incorrecto.",
"You already have the mailAlias": "Ya tienes este alias de correo",
"The alias cant be modified": "Este alias de correo no puede ser modificado",
"No tickets to invoice": "No hay tickets para facturar",
>>>>>>> 5918c14d41259e9989b63c8a36f0e23612cf5d69
"This ticket already has a cmr saved": "Este ticket ya tiene un cmr guardado",
"Name should be uppercase": "El nombre debe ir en mayúscula",
"Bank entity must be specified": "La entidad bancaria es obligatoria",
"An email is necessary": "Es necesario un email",
"You cannot update these fields": "No puedes actualizar estos campos",
"CountryFK cannot be empty": "El país no puede estar vacío",
<<<<<<< HEAD
"Cmr file does not exist": "El archivo del cmr no existe",
"You are not allowed to modify the alias": "No estás autorizado a modificar el alias",
"No tickets to invoice": "No hay tickets para facturar"
=======
"Cmr file does not exist": "El archivo del cmr no existe"
>>>>>>> 5918c14d41259e9989b63c8a36f0e23612cf5d69
}

View File

@ -1,7 +1,14 @@
const SalixError = require('../../util/salixError');
const UserError = require('../../util/user-error');
const SalixError = require('vn-loopback/util/salixError');
const UserError = require('vn-loopback/util/user-error');
const logToConsole = require('strong-error-handler/lib/logger');
const valueIsNot = require('./value-is-not');
const valueInvalid = require('./value-invalid');
const mapMethods = require('vn-loopback/util/map-methods');
const validations = [
valueIsNot,
valueInvalid,
mapMethods
];
module.exports = function() {
return function(err, req, res, next) {
// Thrown user errors
@ -11,7 +18,19 @@ module.exports = function() {
}
// Validation errors
if (err.statusCode == 422) {
if ([400, 422].includes(err.statusCode)) {
try {
validations.forEach(validation => {
if (validation.validation(err.message)) {
const error = validation.handleError(req, err);
if (error)
err.message = validation.message(error, req);
}
});
return next(err);
} catch (e) {
}
try {
let code;
let {messages} = err.details;
@ -26,7 +45,6 @@ module.exports = function() {
return next(new UserError(req.__(err.sqlMessage)));
// Logs error to console
let env = process.env.NODE_ENV;
let useCustomLogging = env && env != 'development' &&
(!err.statusCode || err.statusCode >= 500);

View File

@ -0,0 +1,59 @@
const valueIsNot = require('../value-is-not');
fdescribe('Value is not', () => {
const i18n = require('i18n');
const userId = 9;
const ctx = {
req: {
accessToken: {userId: userId},
headers: {origin: 'http://localhost:5000'},
}
};
fit('UpdateFiscalData endpoint', () => {
let messageError = 'Value is not number';
const tag = 'provinceFk';
try {
expect(valueIsNot.validation(messageError)).toBeTrue();
const data = {
method: 'PATCH',
originalUrl: '/api/supplier/updateFiscalData',
body: {
[tag]: null
},
__: i18n
};
const result = valueIsNot.handleError(data);
expect(result.tag).toEqual(tag);
expect(valueIsNot.message(result, i18n)).toEqual('El campo \'provincia\' no es válido');
} catch (error) {
expect(error).toBeDefined();
}
});
describe('OsTicket', () => {
let messageError = 'Value is not object';
const tag = 'additionalData';
it('sendToSupport endpoint', () => {
try {
expect(valueIsNot.validation(messageError)).toBeTrue();
const data = {
method: 'POST',
originalUrl: '/api/OsTickets/send-to-support?access_token=DEFAULT_TOKEN',
body: {
[tag]: '{ \'foo\': 42 }'
}
};
const result = valueIsNot.handleError(data);
expect(result.tag).toEqual(tag);
expect(valueIsNot.message(tag, i18n)).toEqual(`El campo '${tag}' no es válido`);
} catch (error) {
expect(error).toBeDefined();
}
});
});
});

View File

@ -0,0 +1,58 @@
const SLASH = '/';
const $t = require('i18n');
const {models} = require('vn-loopback/server/server');
const mapLocale = require('../../util/map-locales');
module.exports = {
validation: message => String(message).includes('is not valid'),
message: ({tagValue}, {__: $t}) =>
$t('Field are invalid', {tag: tagValue}),
handleError: ({method: verb, originalUrl, body}, err) => {
let tag = null;
let module = null;
let moduleOriginal = null;
let path = null;
try {
if (originalUrl.includes('?'))
originalUrl = originalUrl.split('?')[0];
originalUrl = originalUrl.split('api/')[1];
[module, ...path] = originalUrl.split(SLASH);
moduleOriginal = module;
let model = models[module];
// Capitalize
if (!model) {
module = module.charAt(0).toUpperCase() + module.slice(1);
model = models[module];
}
// Singular
if (!model) {
module = module.substring(0, module.length - 1);
model = models[module];
}
if (!model) throw new Error('No matching model found');
tag = Object.keys(err.details.codes)[0];
if (tag) {
let tagValue = mapLocale[$t.getLocale()][tag];
if (!tagValue) tagValue = tag;
return {tag, tagValue};
}
} catch (error) {
throw new Error(error);
}
}
};
function isJsonString(str) {
try {
let json = JSON.parse(str);
return (typeof json === 'object');
} catch (e) {
return false;
}
}

View File

@ -0,0 +1,106 @@
const SLASH = '/';
const {models} = require('vn-loopback/server/server');
const $t = require('i18n');
const mapLocale = require('../../util/map-locales');
module.exports = {
validation: message => String(message).startsWith('Value is not'),
message: ({tagValue}, {__: $t}) =>
$t('Field are invalid', {tag: tagValue}),
handleError: ({method: verb, originalUrl, body}) => {
let tag = null;
let module = null;
let path = null;
let hasId = false;
try {
if (originalUrl.includes('?'))
originalUrl = originalUrl.split('?')[0];
originalUrl = originalUrl.split('api/')[1];
[module, ...path] = originalUrl.split(SLASH);
hasId = path.length > 1;
let model = models[module];
// Capitalize
if (!model) {
module = module.charAt(0).toUpperCase() + module.slice(1);
model = models[module];
}
// Singular
if (!model) {
module = module.substring(0, module.length - 1);
model = models[module];
}
if (!model) throw new Error('No matching model found');
const currentMethod = model.sharedClass.methods().find(method => {
const methodMatch = [method.http].flat().filter(el => el.verb === verb.toLowerCase()).find(el => {
let isValid = false;
if (hasId)
isValid = el.path.replace(':id', path[0]) === SLASH + path.join(SLASH);
else
isValid = el.path.endsWith(path[0]);
return isValid;
});
if (methodMatch)
return method;
}
);
if (!currentMethod) throw new Error('No matching currentMethod found');
const {accepts} = currentMethod;
for (const [key, value] of Object.entries(body)) {
if (!value) {
tag = key;
break;
}
const accept = accepts.find(acc => acc.arg === key);
if (accept.type !== 'any') {
let isValid = false;
if (value) {
switch (accept.type) {
case 'object':
isValid = isJsonString(value);
break;
case 'number':
isValid = /^[0-9]*$/.test(value);
break;
case 'boolean':
isValid = value instanceof Boolean;
break;
case 'date':
isValid = (new Date(date) !== 'Invalid Date') && !isNaN(new Date(date));
break;
case 'string':
isValid = typeof value == 'string';
break;
}
}
if (!isValid) {
tag = key;
break;
}
}
}
if (tag) {
let tagValue = mapLocale[$t.getLocale()][tag];
if (!tagValue) tagValue = tag;
return {tag, tagValue};
}
} catch (error) {
throw new Error(error);
}
}
};
function isJsonString(str) {
try {
let json = JSON.parse(str);
return (typeof json === 'object');
} catch (e) {
return false;
}
}

View File

@ -0,0 +1,23 @@
const SLASH = '/';
const MODULES = 'modules';
const BACK = 'back';
const path = require('path');
const glob = require('glob');
const modulesPath = `${MODULES}/**/${BACK}/locale/**/**.yml`;
const pathResolve = path.resolve(modulesPath);
const modelsLocale = glob.sync(pathResolve, {}).reduce((acc, f) => {
const file = require(f);
const model = f.substring(f.indexOf(MODULES), f.indexOf(BACK) - 1).split(SLASH)[1];
const locale = path.parse(f).base.split('.')[0];
if (!acc[locale]) acc[locale] = {};
acc[locale] = Object.assign(acc[locale], file.columns);
return acc;
}, {}
);
function keyMap(model, local, connector = '_') {
return `${model}${connector}${local}`;
}
module.exports =modelsLocale;

View File

@ -0,0 +1,12 @@
const SLASH = '/';
const MODULES = 'modules';
const BACK = 'back';
const app = require('vn-loopback/server/server');
const modelsMethods = app;
function keyMap(model, local, connector = '_') {
return `${model}${connector}${local}`;
}
module.exports = modelsMethods;

View File

@ -26,7 +26,7 @@ module.exports = Self => {
},
{
arg: 'street',
type: 'string'
type: 'any'
},
{
arg: 'postcode',
@ -94,7 +94,7 @@ module.exports = Self => {
},
{
arg: 'despiteOfClient',
type: 'number'
type: 'any'
},
{
arg: 'hasIncoterms',

View File

@ -21,6 +21,7 @@
"form-data": "^4.0.0",
"fs-extra": "^5.0.0",
"ftps": "^1.2.0",
"glob": "^10.3.10",
carlossa marked this conversation as resolved Outdated
Outdated
Review

?

?

Esto queda por quitar @carlossa

Esto queda por quitar @carlossa
"gm": "^1.25.0",
"got": "^10.7.0",
"helmet": "^3.21.2",

View File

@ -29,6 +29,9 @@ dependencies:
ftps:
specifier: ^1.2.0
version: 1.2.0
glob:
specifier: ^10.3.10
version: 10.3.10
gm:
specifier: ^1.25.0
version: 1.25.0
@ -1625,7 +1628,6 @@ packages:
strip-ansi-cjs: /strip-ansi@6.0.1
wrap-ansi: 8.1.0
wrap-ansi-cjs: /wrap-ansi@7.0.0
dev: true
/@istanbuljs/load-nyc-config@1.1.0:
resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==}
@ -1913,7 +1915,6 @@ packages:
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'}
requiresBuild: true
dev: true
optional: true
/@puppeteer/browsers@1.9.1:
@ -3027,7 +3028,6 @@ packages:
/ansi-regex@6.0.1:
resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==}
engines: {node: '>=12'}
dev: true
/ansi-styles@2.2.1:
resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==}
@ -3049,7 +3049,6 @@ packages:
/ansi-styles@6.2.1:
resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==}
engines: {node: '>=12'}
dev: true
/ansi-wrap@0.1.0:
resolution: {integrity: sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==}
@ -5207,7 +5206,6 @@ packages:
/eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
dev: true
/ecc-jsbn@0.1.2:
resolution: {integrity: sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==}
@ -5266,7 +5264,6 @@ packages:
/emoji-regex@9.2.2:
resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==}
dev: true
/emojis-list@3.0.0:
resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==}
@ -6102,7 +6099,6 @@ packages:
dependencies:
cross-spawn: 7.0.3
signal-exit: 4.1.0
dev: true
/forever-agent@0.6.1:
resolution: {integrity: sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==}
@ -6496,7 +6492,6 @@ packages:
minimatch: 9.0.3
minipass: 7.0.4
path-scurry: 1.10.1
dev: true
/glob@3.2.11:
resolution: {integrity: sha512-hVb0zwEZwC1FXSKRPFTeOtN7AArJcJlI6ULGLtrstaswKNlrTJqAA+1lYlSUop4vjA423xlBzqfVS3iWGlqJ+g==}
@ -6511,7 +6506,7 @@ packages:
fs.realpath: 1.0.0
inflight: 1.0.6
inherits: 2.0.4
minimatch: 3.0.8
minimatch: 3.1.2
once: 1.4.0
path-is-absolute: 1.0.1
dev: true
@ -8005,7 +8000,6 @@ packages:
'@isaacs/cliui': 8.0.2
optionalDependencies:
'@pkgjs/parseargs': 0.11.0
dev: true
/jade@0.26.3:
resolution: {integrity: sha512-mkk3vzUHFjzKjpCXeu+IjXeZD+QOTjUUdubgmHtHTDwvAO2ZTkMTTVrapts5CWz3JvJryh/4KWZpjeZrCepZ3A==}
@ -9254,7 +9248,6 @@ packages:
/lru-cache@10.2.0:
resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==}
engines: {node: 14 || >=16.14}
dev: true
/lru-cache@2.7.3:
resolution: {integrity: sha512-WpibWJ60c3AgAz8a2iYErDrcT2C7OmKnsWhIcHOjkUHFjkXncJhtLxNSqUmxRxRunpb5I8Vprd7aNSd2NtksJQ==}
@ -9660,7 +9653,6 @@ packages:
engines: {node: '>=16 || 14 >=14.17'}
dependencies:
brace-expansion: 2.0.1
dev: true
/minimist-options@4.1.0:
resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==}
@ -9750,7 +9742,6 @@ packages:
/minipass@7.0.4:
resolution: {integrity: sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==}
engines: {node: '>=16 || 14 >=14.17'}
dev: true
/minizlib@1.3.3:
resolution: {integrity: sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==}
@ -10845,7 +10836,6 @@ packages:
dependencies:
lru-cache: 10.2.0
minipass: 7.0.4
dev: true
/path-to-regexp@0.1.7:
resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==}
@ -12176,7 +12166,6 @@ packages:
/signal-exit@4.1.0:
resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==}
engines: {node: '>=14'}
dev: true
/simple-concat@1.0.1:
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
@ -12633,7 +12622,6 @@ packages:
eastasianwidth: 0.2.0
emoji-regex: 9.2.2
strip-ansi: 7.1.0
dev: true
/string_decoder@0.10.31:
resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==}
@ -12680,7 +12668,6 @@ packages:
engines: {node: '>=12'}
dependencies:
ansi-regex: 6.0.1
dev: true
/strip-bom@2.0.0:
resolution: {integrity: sha512-kwrX1y7czp1E69n2ajbG65mIo9dqvJ+8aBQXOGVxqwvNbsXdFM6Lq37dLAY3mknUwru8CfcCbfOLL/gMo+fi3g==}
@ -14183,7 +14170,6 @@ packages:
ansi-styles: 6.2.1
string-width: 5.1.2
strip-ansi: 7.1.0
dev: true
/wrappy@1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}