- Excel, CSV(; , ou tabulação) e TXT são agora aceitos para upload. - Formato de dados atualizado para arquivos que fogem do padrão pré definido.
124 lines
3.5 KiB
JavaScript
124 lines
3.5 KiB
JavaScript
const axios = require('axios');
|
|
const fs = require('fs');
|
|
const readline = require('readline');
|
|
const path = require('path');
|
|
const XLSX = require('xlsx');
|
|
const { apiConfig, apiViabilidadeUrl, apiUrlBase } = require('../config/apiConfig');
|
|
|
|
function normalizeHeader(value) {
|
|
return String(value || '')
|
|
.trim()
|
|
.toLowerCase()
|
|
.normalize('NFD')
|
|
.replace(/[\u0300-\u036f]/g, '')
|
|
.replace(/[_-]+/g, ' ')
|
|
.replace(/\s+/g, ' ');
|
|
}
|
|
|
|
function hasHeader(headers, aliases) {
|
|
const normalizedAliases = aliases.map(normalizeHeader);
|
|
return headers.some(header => normalizedAliases.includes(header));
|
|
}
|
|
|
|
function isExcelFile(filePath) {
|
|
return ['.xls', '.xlsx'].includes(path.extname(filePath).toLowerCase());
|
|
}
|
|
|
|
function detectDelimiter(line) {
|
|
const delimiters = [';', '\t', ','];
|
|
return delimiters
|
|
.map(delimiter => ({ delimiter, count: line.split(delimiter).length }))
|
|
.sort((a, b) => b.count - a.count)[0].delimiter;
|
|
}
|
|
|
|
function readExcelHeaders(filePath) {
|
|
const workbook = XLSX.readFile(filePath, { cellDates: false, raw: false });
|
|
const firstSheetName = workbook.SheetNames[0];
|
|
if (!firstSheetName) return [];
|
|
|
|
const rows = XLSX.utils.sheet_to_json(workbook.Sheets[firstSheetName], {
|
|
header: 1,
|
|
blankrows: false,
|
|
defval: ''
|
|
});
|
|
|
|
return (rows[0] || []).map(normalizeHeader);
|
|
}
|
|
|
|
async function readDelimitedHeaders(filePath) {
|
|
const instream = fs.createReadStream(filePath, { encoding: 'utf8' });
|
|
const rl = readline.createInterface({ input: instream, crlfDelay: Infinity });
|
|
|
|
for await (const rawLine of rl) {
|
|
const line = rawLine.replace(/^\uFEFF/, '').replace(/\r$/, '');
|
|
if (!line.trim()) continue;
|
|
rl.close();
|
|
return line.split(detectDelimiter(line)).map(normalizeHeader);
|
|
}
|
|
|
|
rl.close();
|
|
return [];
|
|
}
|
|
|
|
function hasCepHeader(headers) {
|
|
return headers.some(header => /\bcep\b/.test(header) || header === 'codigo postal');
|
|
}
|
|
|
|
function hasAddressOrNumberHeader(headers) {
|
|
return headers.some(header => ['numero', 'num', 'nº', 'n°'].includes(header)
|
|
|| header.includes('endereco')
|
|
|| header.includes('logradouro'));
|
|
}
|
|
|
|
async function consultarViabilidade(data) {
|
|
try {
|
|
const dataType = await discoverDataType(data);
|
|
let endpoint = apiUrlBase;
|
|
if (dataType === 'geolocalizacao') {
|
|
endpoint += 'viabilidade/lat-long';
|
|
} else {
|
|
endpoint += 'viabilidade';
|
|
}
|
|
const response = await axios.post(endpoint, data, {
|
|
timeout: 10000,
|
|
headers: { 'Content-Type': 'application/json' }
|
|
});
|
|
console.log('Resposta da API de viabilidade:', response.data);
|
|
return (response.data);
|
|
} catch (error) {
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
|
|
// Preciso de uma função para verificar se os dados vindos são de CEP ou de geolocalização
|
|
async function discoverDataType(input) {
|
|
if (typeof input === 'string') {
|
|
const headers = isExcelFile(input)
|
|
? readExcelHeaders(input)
|
|
: await readDelimitedHeaders(input);
|
|
|
|
const hasCepNumero = hasCepHeader(headers) && hasAddressOrNumberHeader(headers);
|
|
if (hasCepNumero) {
|
|
return 'cep';
|
|
} else if (headers.includes('latitude') && headers.includes('longitude')) {
|
|
return 'geolocalizacao';
|
|
} else {
|
|
return 'unknown';
|
|
}
|
|
} else if (typeof input === 'object') {
|
|
// Trata como objeto de dados
|
|
if (input.cep && input.numero) {
|
|
return 'cep';
|
|
} else if (input.latitude && input.longitude) {
|
|
return 'geolocalizacao';
|
|
} else {
|
|
return 'unknown';
|
|
}
|
|
} else {
|
|
return 'unknown';
|
|
}
|
|
}
|
|
|
|
module.exports = { consultarViabilidade, discoverDataType };
|