REFAC: Refatoração da validação de CSV para ampliar os padrões de planilhas de viabilidade. #1

Merged
gabriel.pereira merged 1 commits from develop into master 2026-06-25 15:14:32 -03:00
2 changed files with 23 additions and 7 deletions
Showing only changes of commit 011f7b8c47 - Show all commits

View File

@ -132,8 +132,9 @@ function hasAddressOrNumberHeader(headers) {
} }
function hasGeoHeaders(headers) { function hasGeoHeaders(headers) {
return hasHeaderAlias(headers, ['latitude', 'lat']) const norm = headers.map(normalizeHeader);
&& hasHeaderAlias(headers, ['longitude', 'long', 'lng', 'lon']); return norm.some(h => /\blat(itude)?\b/.test(h))
&& norm.some(h => /\blo?n[g]?(itude)?\b/.test(h));
} }
function findHeaderRowIndex(rows) { function findHeaderRowIndex(rows) {
@ -152,8 +153,10 @@ function resolveColumnIndexes(headers) {
idxCep: findFirstHeaderIndex(headers, header => /\bcep\b/.test(header) || header === 'codigo postal'), idxCep: findFirstHeaderIndex(headers, header => /\bcep\b/.test(header) || header === 'codigo postal'),
idxNumero: exactIndex(['numero', 'número', 'num', 'nº', 'n°']), idxNumero: exactIndex(['numero', 'número', 'num', 'nº', 'n°']),
idxEndereco: findFirstHeaderIndex(headers, header => header.includes('endereco') || header.includes('logradouro')), idxEndereco: findFirstHeaderIndex(headers, header => header.includes('endereco') || header.includes('logradouro')),
idxLatitude: exactIndex(['latitude', 'lat']), // Antes: exactIndex(['latitude', 'lat'])
idxLongitude: exactIndex(['longitude', 'long', 'lng', 'lon']) idxLatitude: findFirstHeaderIndex(headers, header => /\blat(itude)?\b/.test(header)),
// Antes: exactIndex(['longitude', 'long', 'lng', 'lon'])
idxLongitude: findFirstHeaderIndex(headers, header => /\blo?n[g]?(itude)?\b/.test(header)),
}; };
} }
@ -187,7 +190,20 @@ function buildCepPayload(cols, indexes) {
} }
function parseCoordinate(value) { function parseCoordinate(value) {
const parsed = parseFloat(String(value ?? '').trim().replace(',', '.')); const str = String(value ?? '')
.replace(/[\u00A0\u202F\u2000-\u200B\u3000]/g, '') // Bug 2: remove non-breaking spaces
.trim()
.replace(',', '.');
// Bug 3: converte DMS "17 38 18.80 S" → -17.638556
const dms = str.match(/^(\d+)[°\s]+(\d+)['\s]+(\d+(?:\.\d+)?)["\s]*([NSEW])?$/i);
if (dms) {
const decimal = parseFloat(dms[1]) + parseFloat(dms[2]) / 60 + parseFloat(dms[3]) / 3600;
const negative = /[SW]/i.test(dms[4] ?? '');
return negative ? -decimal : decimal;
}
const parsed = parseFloat(str);
return Number.isFinite(parsed) ? parsed : NaN; return Number.isFinite(parsed) ? parsed : NaN;
} }

View File

@ -105,8 +105,8 @@ function hasAddressOrNumberHeader(headers) {
} }
function hasGeoHeaders(headers) { function hasGeoHeaders(headers) {
return hasHeader(headers, ['latitude', 'lat']) return headers.some(h => /\blat(itude)?\b/.test(h))
&& hasHeader(headers, ['longitude', 'long', 'lng', 'lon']); && headers.some(h => /\blo?n[g]?(itude)?\b/.test(h));
} }
async function consultarViabilidade(data) { async function consultarViabilidade(data) {