- Trazer duas caixas como alternativa. O que falta: - Fazer viabilidade a partir da distância do Trajeto. - Mudar pastas autorizadas do geogrid.
96 lines
4.4 KiB
JavaScript
96 lines
4.4 KiB
JavaScript
const geogridService = require('../../shared/apis/geogridService.js');
|
||
const apiConfig = require('../../shared/config/apiConfig.js');
|
||
const logger = require('../../shared/utils/logger.js');
|
||
const { mapWithConcurrency } = require('../../shared/utils/concurrency.js');
|
||
|
||
// Regra de negócio PURA: dada uma distância (em metros), define quais serviços
|
||
// estão disponíveis. É a mesma regra de sempre — o que muda é a distância que
|
||
// alimenta ela (agora a real de trajeto). Isolada e testável.
|
||
function classificarPorDistancia(distancia) {
|
||
if (distancia == null || typeof distancia !== 'number' || Number.isNaN(distancia)) {
|
||
return { dedicado: false, naoDedicado: false };
|
||
}
|
||
if (distancia <= 500) return { dedicado: true, naoDedicado: true };
|
||
if (distancia <= 1000) return { dedicado: true, naoDedicado: false };
|
||
return { dedicado: false, naoDedicado: false }; // 1001–5000m: caixa existe, mas fora do alcance
|
||
}
|
||
|
||
// Núcleo de orquestração: a partir de coordenadas de origem (endereço),
|
||
// 1) acha as N caixas mais próximas em linha reta (GeoGrid),
|
||
// 2) calcula a distância REAL de trajeto até cada uma e pega a menor,
|
||
// 3) classifica a viabilidade sobre a distância real (com fallback p/ reta).
|
||
//
|
||
// Retorna um resultado de domínio NEUTRO (sem formato de resposta HTTP):
|
||
// { distancia, distanciaReta, distanciaReal, dedicado, naoDedicado, provedor }
|
||
// - `distancia` é a EFETIVA usada na regra: real quando disponível, senão reta.
|
||
async function avaliarPorCoordenadas(origem, { modo = apiConfig.geogridTrajetoModo, topN, misturarProvedores = false } = {}) {
|
||
const { provedor, caixas } = await geogridService.consultarCaixasProximas(origem.lat, origem.lon, { topN, misturarProvedores });
|
||
|
||
// Sem caixa no raio: mantém o comportamento histórico ("5KM+", nada viável).
|
||
if (!caixas || caixas.length === 0) {
|
||
return {
|
||
distancia: "5KM+",
|
||
distanciaReta: null,
|
||
distanciaReal: null,
|
||
dedicado: false,
|
||
naoDedicado: false,
|
||
provedor,
|
||
caixas: []
|
||
};
|
||
}
|
||
|
||
// Para cada caixa (na ordem do GeoGrid = por distância em linha reta),
|
||
// calcula a distância real de trajeto e classifica individualmente.
|
||
const detalhes = await mapWithConcurrency(caixas, apiConfig.geogridConcurrency, async (caixa) => {
|
||
let distanciaReal = null;
|
||
if (caixa.lat != null && caixa.lon != null) {
|
||
try {
|
||
const trajeto = await geogridService.consultaTrajeto(origem, caixa, modo);
|
||
const d = Number(trajeto && trajeto.distancia);
|
||
distanciaReal = Number.isFinite(d) ? d : null;
|
||
} catch (err) {
|
||
logger.warn('Trajeto falhou para uma caixa, usando linha reta nesta candidata', {
|
||
message: err.message,
|
||
status: err.response?.status,
|
||
data: err.response?.data, // corpo do erro do GeoGrid (motivo do 400)
|
||
url: err.config?.url,
|
||
caixa: { lat: caixa.lat, lon: caixa.lon }
|
||
});
|
||
}
|
||
}
|
||
const distancia = distanciaReal ?? caixa.distanciaReta; // efetiva por caixa (real, senão reta)
|
||
return {
|
||
provedor: caixa.provedor,
|
||
sigla: caixa.sigla,
|
||
lat: caixa.lat,
|
||
lon: caixa.lon,
|
||
distanciaReta: caixa.distanciaReta,
|
||
distanciaReal,
|
||
distancia,
|
||
...classificarPorDistancia(distancia)
|
||
};
|
||
});
|
||
|
||
// Agregado (compatibilidade WordPress): menor distância efetiva entre as caixas.
|
||
const distanciaReta = detalhes[0].distanciaReta ?? null; // caixa mais próxima em linha reta
|
||
const reais = detalhes.map(d => d.distanciaReal).filter(d => d != null);
|
||
const distanciaReal = reais.length ? Math.min(...reais) : null;
|
||
|
||
if (distanciaReal == null) {
|
||
logger.warn('Nenhum trajeto disponível; usando distância em linha reta como fallback', { origem, distanciaReta });
|
||
}
|
||
|
||
const distanciaEfetiva = distanciaReal ?? distanciaReta;
|
||
|
||
return {
|
||
distancia: distanciaEfetiva,
|
||
distanciaReta,
|
||
distanciaReal,
|
||
...classificarPorDistancia(distanciaEfetiva),
|
||
provedor,
|
||
caixas: detalhes // detalhe por caixa (mais próxima em linha reta primeiro)
|
||
};
|
||
}
|
||
|
||
module.exports = { classificarPorDistancia, avaliarPorCoordenadas };
|