semillero-INVIMA/backend/invima/adapters.js

279 lines
11 KiB
JavaScript

const crypto = require('crypto');
const { INVIMA_DATASETS } = require('../APIinvima');
const cleanText = (value) => {
if (value === null || value === undefined) return null;
const text = String(value).trim();
if (!text) return null;
if (text.toLowerCase() === 'null') return null;
return text;
};
const pickFirst = (row, keys) => {
for (const key of keys) {
const value = cleanText(row[key]);
if (value) return value;
}
return null;
};
const parseDateFlexible = (value) => {
const text = cleanText(value);
if (!text) return null;
const slashDate = text.match(/^(\d{1,2})\/(\d{1,2})\/(\d{4})$/);
if (slashDate) {
const month = slashDate[1].padStart(2, '0');
const day = slashDate[2].padStart(2, '0');
return `${slashDate[3]}-${month}-${day}`;
}
const parsed = new Date(text);
if (Number.isNaN(parsed.getTime())) return null;
return parsed.toISOString().slice(0, 10);
};
const buildUid = (datasetKey, rawParts, row) => {
const parts = rawParts.map(cleanText).filter(Boolean);
const base = parts.length ? `${datasetKey}|${parts.join('|')}` : `${datasetKey}|${JSON.stringify(row)}`;
return crypto.createHash('sha1').update(base).digest('hex');
};
const baseRecord = (dataset, row) => ({
source_dataset_key: dataset.key,
source_dataset_id: dataset.id,
source_dataset_name: dataset.name,
categoria_linea: dataset.defaultCategory,
expediente: null,
registro_sanitario: null,
producto: null,
titular: null,
estado_registro: null,
fecha_expedicion: null,
fecha_vencimiento: null,
modalidad: null,
grupo: null,
marca: null,
principio_activo: null,
forma_farmaceutica: null,
presentacion_comercial: null,
atc: null,
rol_nombre: null,
rol_tipo: null,
ciudad_titular: null,
pais_titular: null,
fabricante: null,
importador: null,
vigencia: null,
extra: row
});
const buildAdapter = (datasetKey, normalize) => {
const dataset = INVIMA_DATASETS[datasetKey];
if (!dataset) {
throw new Error(`Dataset no configurado en APIinvima.json: ${datasetKey}`);
}
return {
...dataset,
normalize
};
};
const invimaAdapters = {
dispositivos: buildAdapter('dispositivos', (row) => {
const record = baseRecord(INVIMA_DATASETS.dispositivos, row);
record.expediente = cleanText(row.expediente);
record.registro_sanitario = pickFirst(row, ['registro_sanitario']);
record.producto = pickFirst(row, ['prodcuto', 'producto']);
record.titular = cleanText(row.titular);
record.estado_registro = cleanText(row.estado_registro);
record.fecha_vencimiento = parseDateFlexible(row.fecha_vencimiento);
record.modalidad = cleanText(row.modalidad);
record.grupo = cleanText(row.grupo);
record.marca = cleanText(row.marca);
record.rol_nombre = cleanText(row.nombre_rol);
record.rol_tipo = cleanText(row.rol);
record.ciudad_titular = cleanText(row.ciudad_titular);
record.pais_titular = cleanText(row.pais_titular);
record.vigencia = cleanText(row.estado_registro);
return {
...record,
source_uid: buildUid(
'dispositivos',
[row.registro_sanitario, row.expediente, row.prodcuto, row.nombre_rol, row.modalidad],
row
)
};
}),
rs_nso: buildAdapter('rs_nso', (row) => {
const record = baseRecord(INVIMA_DATASETS.rs_nso, row);
record.categoria_linea = cleanText(row.grupo) || INVIMA_DATASETS.rs_nso.defaultCategory;
record.expediente = cleanText(row.expediente);
record.registro_sanitario = cleanText(row.rsynso);
record.producto = cleanText(row.producto);
record.titular = cleanText(row.titular);
record.estado_registro = cleanText(row.estadoregistro);
record.fecha_expedicion = parseDateFlexible(row.fechaexpedicion);
record.fecha_vencimiento = parseDateFlexible(row.fechavencimiento);
record.modalidad = cleanText(row.modalidad);
record.grupo = cleanText(row.grupo);
record.rol_nombre = cleanText(row.nombrerol);
record.rol_tipo = cleanText(row.rol);
record.vigencia = cleanText(row.estadoregistro);
return {
...record,
source_uid: buildUid('rs_nso', [row.rsynso, row.expediente, row.producto, row.nombrerol], row)
};
}),
medicamentos: buildAdapter('medicamentos', (row) => {
const record = baseRecord(INVIMA_DATASETS.medicamentos, row);
record.expediente = cleanText(row.expediente);
record.registro_sanitario = cleanText(row.registrosanitario);
record.producto = cleanText(row.producto);
record.titular = cleanText(row.titular);
record.estado_registro = cleanText(row.estadoregistro);
record.fecha_expedicion = parseDateFlexible(row.fechaexpedicion);
record.fecha_vencimiento = parseDateFlexible(row.fechavencimiento);
record.modalidad = cleanText(row.modalidad);
record.principio_activo = cleanText(row.principioactivo);
record.forma_farmaceutica = cleanText(row.formafarmaceutica);
record.presentacion_comercial = cleanText(row.descripcioncomercial);
record.atc = cleanText(row.atc);
record.rol_nombre = cleanText(row.nombrerol);
record.rol_tipo = cleanText(row.tiporol);
record.vigencia = cleanText(row.estadocum) || cleanText(row.estadoregistro);
return {
...record,
source_uid: buildUid(
'medicamentos',
[row.registrosanitario, row.expedientecum, row.consecutivocum, row.producto],
row
)
};
}),
cum_vigentes: buildAdapter('cum_vigentes', (row) => {
const record = baseRecord(INVIMA_DATASETS.cum_vigentes, row);
record.expediente = cleanText(row.expediente);
record.registro_sanitario = cleanText(row.registrosanitario);
record.producto = cleanText(row.producto);
record.titular = cleanText(row.titular);
record.estado_registro = cleanText(row.estadoregistro);
record.fecha_expedicion = parseDateFlexible(row.fechaexpedicion);
record.modalidad = cleanText(row.modalidad);
record.principio_activo = cleanText(row.principioactivo);
record.forma_farmaceutica = cleanText(row.formafarmaceutica);
record.presentacion_comercial = cleanText(row.descripcioncomercial);
record.atc = cleanText(row.atc);
record.rol_nombre = cleanText(row.nombrerol);
record.rol_tipo = cleanText(row.tiporol);
record.vigencia = cleanText(row.estadocum) || cleanText(row.estadoregistro);
return {
...record,
source_uid: buildUid(
'cum_vigentes',
[row.registrosanitario, row.expedientecum, row.consecutivocum, row.producto],
row
)
};
}),
homeopaticos: buildAdapter('homeopaticos', (row) => {
const record = baseRecord(INVIMA_DATASETS.homeopaticos, row);
record.expediente = cleanText(row.expediente);
record.registro_sanitario = cleanText(row.registro_sanitario);
record.producto = cleanText(row.producto);
record.titular = cleanText(row.titular);
record.estado_registro = cleanText(row.estado_registro);
record.fecha_expedicion = parseDateFlexible(row.fecha_expedicion);
record.modalidad = cleanText(row.modalidad);
record.marca = cleanText(row.marca);
record.principio_activo = cleanText(row.principio_activo);
record.forma_farmaceutica = cleanText(row.forma_farmaceutica);
record.presentacion_comercial = cleanText(row.presentacioncomercial);
record.rol_tipo = cleanText(row.rol);
record.ciudad_titular = cleanText(row.ciudad_titular);
record.vigencia = cleanText(row.estado_registro);
return {
...record,
source_uid: buildUid('homeopaticos', [row.registro_sanitario, row.expediente, row.producto], row)
};
}),
fitoterapeuticos: buildAdapter('fitoterapeuticos', (row) => {
const record = baseRecord(INVIMA_DATASETS.fitoterapeuticos, row);
record.expediente = cleanText(row.expediente);
record.registro_sanitario = cleanText(row.registro_sanitario);
record.producto = cleanText(row.producto);
record.titular = cleanText(row.titular);
record.fecha_expedicion = parseDateFlexible(row.fecha_expedicion);
record.fecha_vencimiento = parseDateFlexible(row.fecha_vencimiento);
record.modalidad = cleanText(row.modalidad);
record.marca = cleanText(row.marca);
record.principio_activo = cleanText(row.principio_activo);
record.forma_farmaceutica = cleanText(row.forma_farmaceutica);
record.presentacion_comercial = cleanText(row.presentacioncomercial);
record.rol_tipo = cleanText(row.rol);
record.ciudad_titular = cleanText(row.ciudad_titular);
record.vigencia = cleanText(row.fecha_vencimiento);
return {
...record,
source_uid: buildUid('fitoterapeuticos', [row.registro_sanitario, row.expediente, row.producto], row)
};
}),
suplementos: buildAdapter('suplementos', (row) => {
const record = baseRecord(INVIMA_DATASETS.suplementos, row);
record.expediente = cleanText(row.expediente);
record.registro_sanitario = cleanText(row.registro_sanitario);
record.producto = cleanText(row.producto);
record.titular = cleanText(row.titular);
record.estado_registro = cleanText(row.estado_registro);
record.fecha_expedicion = parseDateFlexible(row.fecha_expedicion);
record.fecha_vencimiento = parseDateFlexible(row.fecha_vencimiento);
record.modalidad = cleanText(row.modalidad);
record.marca = cleanText(row.marca);
record.forma_farmaceutica = cleanText(row.forma_farmaceutica);
record.presentacion_comercial = cleanText(row.presentacioncomercial);
record.ciudad_titular = cleanText(row.ciudad_titular);
record.vigencia = cleanText(row.estado_registro);
return {
...record,
source_uid: buildUid('suplementos', [row.registro_sanitario, row.expediente, row.producto], row)
};
}),
vacunas: buildAdapter('vacunas', (row) => {
const record = baseRecord(INVIMA_DATASETS.vacunas, row);
record.expediente = cleanText(row.expediente);
record.registro_sanitario = cleanText(row.registro_sanitario);
record.producto = cleanText(row.producto);
record.titular = cleanText(row.titular);
record.estado_registro = cleanText(row.vigencia);
record.modalidad = cleanText(row.via_de_administraci_n);
record.principio_activo = cleanText(row.principio_activo);
record.forma_farmaceutica = cleanText(row.forma_farmac_utica);
record.presentacion_comercial = cleanText(row.presentaci_n_comercial);
record.atc = cleanText(row.atc);
record.fabricante = cleanText(row.fabricante);
record.importador = cleanText(row.importador);
record.vigencia = cleanText(row.vigencia);
return {
...record,
source_uid: buildUid('vacunas', [row.consec, row.registro_sanitario, row.expediente, row.producto], row)
};
})
};
const adapterKeys = Object.keys(invimaAdapters);
module.exports = {
invimaAdapters,
adapterKeys,
cleanText,
parseDateFlexible,
pickFirst
};