FEAT: Ajustado para uso da geolocalização antes do CEP

This commit is contained in:
Rafael Alves Lopes 2026-05-05 16:05:49 -03:00
parent e42621642b
commit 5b98394ee2
2 changed files with 61 additions and 31 deletions

View File

@ -117,7 +117,8 @@ function hasAddressOrNumberHeader(headers) {
function hasGeoHeaders(headers) {
const normalizedHeaders = headers.map(normalizeHeader);
return normalizedHeaders.includes('latitude') && normalizedHeaders.includes('longitude');
return normalizedHeaders.some(header => header.includes('latitude'))
&& normalizedHeaders.some(header => header.includes('longitude'));
}
function findHeaderRowIndex(rows) {
@ -136,8 +137,8 @@ function resolveColumnIndexes(headers) {
idxCep: findFirstHeaderIndex(headers, header => /\bcep\b/.test(header) || header === 'codigo postal'),
idxNumero: exactIndex(['numero', 'número', 'num', 'nº', 'n°']),
idxEndereco: findFirstHeaderIndex(headers, header => header.includes('endereco') || header.includes('logradouro')),
idxLatitude: exactIndex(['latitude']),
idxLongitude: exactIndex(['longitude'])
idxLatitude: findFirstHeaderIndex(headers, header => header.includes('latitude')),
idxLongitude: findFirstHeaderIndex(headers, header => header.includes('longitude'))
};
}
@ -170,13 +171,52 @@ function buildCepPayload(cols, indexes) {
return { cep, numero };
}
function parseCoordinate(value) {
const parsed = parseFloat(String(value ?? '').trim().replace(',', '.'));
return Number.isFinite(parsed) ? parsed : NaN;
}
function buildGeoPayload(cols, indexes) {
const latitude = indexes.idxLatitude >= 0 ? parseCoordinate(cols[indexes.idxLatitude]) : NaN;
const longitude = indexes.idxLongitude >= 0 ? parseCoordinate(cols[indexes.idxLongitude]) : NaN;
if (isNaN(latitude) || isNaN(longitude)) return null;
return { latitude, longitude };
}
async function consultarComFallback(geoPayload, cepPayload) {
let lastError = null;
if (geoPayload) {
try {
const result = await consultarViabilidade(geoPayload);
if (!result || !result.error) return result;
lastError = new Error(result.error);
} catch (err) {
lastError = err;
}
}
if (cepPayload) {
try {
const result = await consultarViabilidade(cepPayload);
if (!result || !result.error) return result;
lastError = new Error(result.error);
} catch (err) {
lastError = err;
}
}
throw lastError || new Error('Linha sem latitude/longitude ou CEP valido');
}
function cleanCsvValue(value) {
const text = String(value ?? '').replace(/[\r\n;]/g, ' ');
return text.includes('"') ? text.replace(/"/g, "'") : text;
}
async function countValidLines(inputPath) {
const dataType = await discoverDataType(inputPath);
await discoverDataType(inputPath);
const rows = readRows(inputPath);
const headerRowIndex = findHeaderRowIndex(rows);
const headers = rows[headerRowIndex] || [];
@ -184,20 +224,16 @@ async function countValidLines(inputPath) {
let total = 0;
for (const cols of rows.slice(headerRowIndex + 1)) {
if (dataType === 'cep') {
if (buildCepPayload(cols, indexes)) total++;
} else if (dataType === 'geolocalizacao') {
const latitude = indexes.idxLatitude >= 0 ? parseFloat(cols[indexes.idxLatitude]) : NaN;
const longitude = indexes.idxLongitude >= 0 ? parseFloat(cols[indexes.idxLongitude]) : NaN;
if (!isNaN(latitude) && !isNaN(longitude)) total++;
}
const geoPayload = buildGeoPayload(cols, indexes);
const cepPayload = buildCepPayload(cols, indexes);
if (geoPayload || cepPayload) total++;
}
return total;
}
async function processCsvFile(jobId, inputPath, originalName) {
const dataType = await discoverDataType(inputPath);
await discoverDataType(inputPath);
const rows = readRows(inputPath);
const headerRowIndex = findHeaderRowIndex(rows);
const headers = rows[headerRowIndex] || [];
@ -210,23 +246,12 @@ async function processCsvFile(jobId, inputPath, originalName) {
outStream.write(['Distancia', 'Dedicado', 'Nao Dedicado', 'Erro', ...headers].join(';') + '\n');
for (const cols of rows.slice(headerRowIndex + 1)) {
let dataToSend = {};
if (dataType === 'cep') {
dataToSend = buildCepPayload(cols, indexes);
if (!dataToSend) continue;
} else if (dataType === 'geolocalizacao') {
const latitude = indexes.idxLatitude >= 0 ? parseFloat(cols[indexes.idxLatitude]) : NaN;
const longitude = indexes.idxLongitude >= 0 ? parseFloat(cols[indexes.idxLongitude]) : NaN;
if (isNaN(latitude) || isNaN(longitude)) continue;
dataToSend = { latitude, longitude };
} else {
continue;
}
const geoPayload = buildGeoPayload(cols, indexes);
const cepPayload = buildCepPayload(cols, indexes);
if (!geoPayload && !cepPayload) continue;
try {
const viab = await consultarViabilidade(dataToSend);
const viab = await consultarComFallback(geoPayload, cepPayload);
const distancia = viab.distancia ?? (viab.raw && (viab.raw.distancia || viab.raw.distance)) ?? '';
const dedicado = viab.dedicado ? 'Viavel' : 'Nao Viavel';
const naoDedicado = viab.naoDedicado ? 'Viavel' : 'Nao Viavel';

View File

@ -55,7 +55,7 @@ function findHeaderRow(rows) {
return rows.find(row => {
const headers = row.map(normalizeHeader);
const hasCepNumero = hasCepHeader(headers) && hasAddressOrNumberHeader(headers);
const hasGeo = headers.includes('latitude') && headers.includes('longitude');
const hasGeo = hasGeoHeaders(headers);
return hasCepNumero || hasGeo;
}) || [];
}
@ -83,7 +83,7 @@ async function readDelimitedHeaders(filePath) {
if (!line.trim()) continue;
const headers = line.split(detectDelimiter(line)).map(normalizeHeader);
const hasCepNumero = hasCepHeader(headers) && hasAddressOrNumberHeader(headers);
const hasGeo = headers.includes('latitude') && headers.includes('longitude');
const hasGeo = hasGeoHeaders(headers);
if (hasCepNumero || hasGeo) {
rl.close();
return headers;
@ -104,6 +104,11 @@ function hasAddressOrNumberHeader(headers) {
|| header.includes('logradouro'));
}
function hasGeoHeaders(headers) {
return headers.some(header => header.includes('latitude'))
&& headers.some(header => header.includes('longitude'));
}
async function consultarViabilidade(data) {
try {
const dataType = await discoverDataType(data);
@ -135,7 +140,7 @@ async function discoverDataType(input) {
const hasCepNumero = hasCepHeader(headers) && hasAddressOrNumberHeader(headers);
if (hasCepNumero) {
return 'cep';
} else if (headers.includes('latitude') && headers.includes('longitude')) {
} else if (hasGeoHeaders(headers)) {
return 'geolocalizacao';
} else {
return 'unknown';
@ -144,7 +149,7 @@ async function discoverDataType(input) {
// Trata como objeto de dados
if (input.cep && input.numero) {
return 'cep';
} else if (input.latitude && input.longitude) {
} else if (input.latitude !== undefined && input.longitude !== undefined) {
return 'geolocalizacao';
} else {
return 'unknown';