diff --git a/src/shared/apis/geogridService.js b/src/shared/apis/geogridService.js index 664c01f..631ac67 100644 --- a/src/shared/apis/geogridService.js +++ b/src/shared/apis/geogridService.js @@ -31,48 +31,58 @@ const fetchRegistros = async (lat, lon) => { logger.info("Resposta do GeoGrid", { totalRegistros: registros.length, - siglas: registros.map(r => r.pasta?.sigla), - autorizadas: apiConfig.geogridAuthorizedSiglasPastas + siglas: registros.map(r => r.pasta?.sigla) }); return registros; }; -// Seleção de registros por prioridade: autorizados (rede própria) > parceiros > nenhum. -// Retorna a LISTA ordenada (por distância, como veio do GeoGrid) + o provedor resolvido. -// Elegibilidade de um registro: rede própria (sigla autorizada) ou parceiro. -// Siglas fora disso (sub-projetos, etc.) NÃO são consideradas viabilidade. -const ehAutorizado = (sigla) => apiConfig.geogridAuthorizedSiglasPastas.includes(sigla); -const ehParceiro = (sigla) => !!sigla && (sigla.toLowerCase().includes("parceiro -") || sigla.toLowerCase().includes("parceiros - outros")); -const ehElegivel = (registro) => { - const sigla = registro && registro.pasta && registro.pasta.sigla; - return ehAutorizado(sigla) || ehParceiro(sigla); +// Classificação da sigla da pasta por convenção de PREFIXO: +// "s-..." => Sothis (rede própria) +// "p-..." => Parceiro; o provedor é o nome que vem depois do "-" +// segmento "sub" após "-" => subterrâneo; prefixa "(Subterrâneo) " no provedor +// Exemplos: "s-Barueri" => "Sothis"; "p-Vivo" => "Vivo"; "s-sub-Barueri" => "(Subterrâneo) Sothis". +// Qualquer outra coisa => não elegível (tipo "nenhum"). +const classificarSigla = (sigla) => { + const partes = String(sigla || '').split('-').map(p => p.trim()).filter(Boolean); + const prefixo = (partes[0] || '').toLowerCase(); + const subterraneo = partes.slice(1).some(p => p.toLowerCase() === 'sub'); + const resto = partes.slice(1).filter(p => p.toLowerCase() !== 'sub'); + + let tipo, nome; + if (prefixo === 's') { + tipo = 'autorizado'; + nome = 'Sothis'; + } else if (prefixo === 'p') { + tipo = 'parceiro'; + nome = resto.join(' ') || 'Parceiro'; + } else { + return { tipo: 'nenhum', provedor: sigla || 'Desconhecido' }; + } + return { tipo, provedor: subterraneo ? `(Subterrâneo) ${nome}` : nome }; }; +const ehAutorizado = (sigla) => classificarSigla(sigla).tipo === 'autorizado'; +const ehParceiro = (sigla) => classificarSigla(sigla).tipo === 'parceiro'; +const ehElegivel = (registro) => classificarSigla(registro && registro.pasta && registro.pasta.sigla).tipo !== 'nenhum'; +const provedorDoRegistro = (registro) => classificarSigla(registro && registro.pasta && registro.pasta.sigla).provedor; + const selecionarRegistros = (registros) => { const autorizados = registros.filter(r => ehAutorizado(r.pasta && r.pasta.sigla)); if (autorizados.length > 0) { - return { provedor: "Sothis", tipo: "autorizado", registros: autorizados }; + return { provedor: provedorDoRegistro(autorizados[0]), tipo: "autorizado", registros: autorizados }; } const parceiros = registros.filter(r => ehParceiro(r.pasta && r.pasta.sigla)); if (parceiros.length > 0) { - return { provedor: parceiros[0].pasta.sigla, tipo: "parceiro", registros: parceiros }; + return { provedor: provedorDoRegistro(parceiros[0]), tipo: "parceiro", registros: parceiros }; } return { provedor: "Nenhum provedor disponível", tipo: "nenhum", registros: [] }; }; // Normaliza um registro do GeoGrid para o que o core precisa: coordenadas da -// caixa (destino do trajeto) + distância em linha reta + sigla da pasta. -// Resolve o provedor de UM registro: rede própria (sigla autorizada) => "Sothis"; -// caso contrário, a própria sigla da pasta (parceiro/sub-projeto/etc.). -const provedorDoRegistro = (registro) => { - const sigla = registro?.pasta?.sigla; - if (apiConfig.geogridAuthorizedSiglasPastas.includes(sigla)) return "Sothis"; - return sigla || "Desconhecido"; -}; - +// caixa (destino do trajeto) + distância em linha reta + sigla + provedor resolvido. const mapCaixa = (registro) => { const lat = Number(registro?.latitude); const lon = Number(registro?.longitude); @@ -159,4 +169,4 @@ const consultaViabilidade = async (lat, lon) => { } }; -module.exports = { consultaViabilidade, consultarCaixasProximas, consultaTrajeto, mapCaixa }; +module.exports = { consultaViabilidade, consultarCaixasProximas, consultaTrajeto, mapCaixa, classificarSigla }; diff --git a/test/viabilidade.test.js b/test/viabilidade.test.js index bdd49a6..b70e204 100644 --- a/test/viabilidade.test.js +++ b/test/viabilidade.test.js @@ -1,6 +1,3 @@ -// Define siglas autorizadas ANTES de carregar apiConfig (que lê o env no require). -process.env.GEOGRID_AUTHORIZED_SIGLAS_PASTAS = 'São Paulo - SP, TMC'; - const test = require('node:test'); const assert = require('node:assert/strict'); @@ -156,19 +153,29 @@ test('core retorna detalhe por caixa (caixas[]) com provedor por caixa', async ( assert.equal(r.caixas[1].naoDedicado, false); // 900 > 500 }); -test('seleção MISTA: só autorizadas + parceiros (ignora siglas inelegíveis)', async () => { +test('classificarSigla: convenção de prefixos s-/p-/sub', () => { + assert.deepEqual(geogridService.classificarSigla('s-Barueri'), { tipo: 'autorizado', provedor: 'Sothis' }); + assert.deepEqual(geogridService.classificarSigla('p-Vivo'), { tipo: 'parceiro', provedor: 'Vivo' }); + assert.deepEqual(geogridService.classificarSigla('s-sub-Barueri'), { tipo: 'autorizado', provedor: '(Subterrâneo) Sothis' }); + assert.deepEqual(geogridService.classificarSigla('p-sub-Vivo'), { tipo: 'parceiro', provedor: '(Subterrâneo) Vivo' }); + assert.equal(geogridService.classificarSigla('Sub Alameda Santos').tipo, 'nenhum'); + assert.equal(geogridService.classificarSigla('São Paulo - SP').tipo, 'nenhum'); // convenção antiga não é mais elegível + assert.equal(geogridService.classificarSigla('S-SP').provedor, 'Sothis'); // case-insensitive +}); + +test('seleção MISTA: só s-/p- (ignora siglas fora da convenção), com subterrâneo', async () => { const axios = require('axios'); const orig = axios.get; axios.get = async () => ({ data: { registros: [ { latitude: '0', longitude: '0', distancia: '50', pasta: { sigla: 'Sub Alameda Santos' } }, // NÃO elegível (mais próxima) - { latitude: '1', longitude: '1', distancia: '100', pasta: { sigla: 'Parceiro - X' } }, // parceiro - { latitude: '2', longitude: '2', distancia: '200', pasta: { sigla: 'São Paulo - SP' } } // autorizada => Sothis + { latitude: '1', longitude: '1', distancia: '100', pasta: { sigla: 'p-Vivo' } }, // parceiro + { latitude: '2', longitude: '2', distancia: '200', pasta: { sigla: 's-sub-Barueri' } } // Sothis subterrâneo ] } }); try { const r = await realConsultarCaixasProximas(0, 0, { topN: 2, misturarProvedores: true }); assert.equal(r.caixas.length, 2); // sub-alameda excluída - assert.equal(r.caixas[0].provedor, 'Parceiro - X'); - assert.equal(r.caixas[1].provedor, 'Sothis'); + assert.equal(r.caixas[0].provedor, 'Vivo'); + assert.equal(r.caixas[1].provedor, '(Subterrâneo) Sothis'); } finally { axios.get = orig; } @@ -178,13 +185,13 @@ test('seleção PADRÃO (WordPress): prioriza Sothis e ignora parceiro mais pró const axios = require('axios'); const orig = axios.get; axios.get = async () => ({ data: { registros: [ - { latitude: '1', longitude: '1', distancia: '100', pasta: { sigla: 'Parceiro - X' } }, - { latitude: '2', longitude: '2', distancia: '200', pasta: { sigla: 'São Paulo - SP' } } + { latitude: '1', longitude: '1', distancia: '100', pasta: { sigla: 'p-Vivo' } }, + { latitude: '2', longitude: '2', distancia: '200', pasta: { sigla: 's-Barueri' } } ] } }); try { const r = await realConsultarCaixasProximas(0, 0, { topN: 2 }); assert.equal(r.provedor, 'Sothis'); - assert.equal(r.caixas.length, 1); // só a autorizada + assert.equal(r.caixas.length, 1); // só a autorizada (Sothis) assert.equal(r.caixas[0].provedor, 'Sothis'); } finally { axios.get = orig;