Initial commit: LexMind - Plataforma Jurídica Inteligente
This commit is contained in:
169
scripts/buscar-publicacoes.ts
Normal file
169
scripts/buscar-publicacoes.ts
Normal file
@@ -0,0 +1,169 @@
|
||||
#!/usr/bin/env npx ts-node
|
||||
|
||||
/**
|
||||
* Script de Busca Diária de Publicações
|
||||
*
|
||||
* Executa busca de publicações em todos os processos ativos de todos os usuários.
|
||||
* Pode ser executado via cron ou manualmente.
|
||||
*
|
||||
* Uso: npx ts-node scripts/buscar-publicacoes.ts
|
||||
* Ou: node dist/scripts/buscar-publicacoes.js (se compilado)
|
||||
*/
|
||||
|
||||
import { PrismaClient } from '@prisma/client'
|
||||
import { buscarPublicacoesReais, buscarPublicacoesEmLote, PublicacaoEncontrada } from '../src/lib/diarios-service'
|
||||
|
||||
const prisma = new PrismaClient()
|
||||
|
||||
interface BuscaStats {
|
||||
totalProcessos: number
|
||||
processosComNovas: number
|
||||
totalPublicacoes: number
|
||||
erros: string[]
|
||||
inicioEm: Date
|
||||
fimEm?: Date
|
||||
}
|
||||
|
||||
async function buscarPublicacoesDiarias(): Promise<BuscaStats> {
|
||||
const stats: BuscaStats = {
|
||||
totalProcessos: 0,
|
||||
processosComNovas: 0,
|
||||
totalPublicacoes: 0,
|
||||
erros: [],
|
||||
inicioEm: new Date(),
|
||||
}
|
||||
|
||||
console.log('='.repeat(60))
|
||||
console.log(`[${new Date().toISOString()}] Iniciando busca diária de publicações`)
|
||||
console.log('='.repeat(60))
|
||||
|
||||
try {
|
||||
// Busca todos os processos ativos
|
||||
const processos = await prisma.processoMonitorado.findMany({
|
||||
where: { status: 'ATIVO' },
|
||||
select: {
|
||||
id: true,
|
||||
numeroProcesso: true,
|
||||
tribunal: true,
|
||||
userId: true,
|
||||
user: {
|
||||
select: { email: true }
|
||||
}
|
||||
},
|
||||
})
|
||||
|
||||
stats.totalProcessos = processos.length
|
||||
console.log(`\n📋 Total de processos ativos: ${processos.length}`)
|
||||
|
||||
if (processos.length === 0) {
|
||||
console.log('Nenhum processo ativo encontrado.')
|
||||
return stats
|
||||
}
|
||||
|
||||
// Busca publicações em lote com rate limiting (500ms entre requisições)
|
||||
console.log('\n🔍 Buscando publicações nos diários oficiais...\n')
|
||||
|
||||
const resultados = await buscarPublicacoesEmLote(
|
||||
processos.map(p => ({
|
||||
id: p.id,
|
||||
numeroProcesso: p.numeroProcesso,
|
||||
tribunal: p.tribunal,
|
||||
})),
|
||||
500 // delay entre requisições
|
||||
)
|
||||
|
||||
// Processa resultados
|
||||
for (const processo of processos) {
|
||||
const resultado = resultados.get(processo.id)
|
||||
|
||||
if (!resultado) {
|
||||
stats.erros.push(`${processo.numeroProcesso}: Sem resultado`)
|
||||
continue
|
||||
}
|
||||
|
||||
if (!resultado.sucesso) {
|
||||
stats.erros.push(`${processo.numeroProcesso}: ${resultado.erro}`)
|
||||
continue
|
||||
}
|
||||
|
||||
let novasDoProcesso = 0
|
||||
|
||||
for (const pub of resultado.publicacoes) {
|
||||
// Verifica duplicata
|
||||
const existing = await prisma.publicacao.findFirst({
|
||||
where: {
|
||||
processoId: processo.id,
|
||||
dataPublicacao: {
|
||||
gte: new Date(pub.dataPublicacao.toDateString()),
|
||||
lt: new Date(new Date(pub.dataPublicacao).setDate(pub.dataPublicacao.getDate() + 1)),
|
||||
},
|
||||
tipo: pub.tipo,
|
||||
},
|
||||
})
|
||||
|
||||
if (!existing) {
|
||||
await prisma.publicacao.create({
|
||||
data: {
|
||||
processoId: processo.id,
|
||||
dataPublicacao: pub.dataPublicacao,
|
||||
diario: pub.diario,
|
||||
conteudo: pub.conteudo,
|
||||
tipo: pub.tipo,
|
||||
prazoCalculado: pub.prazoCalculado,
|
||||
prazoTipo: pub.prazoTipo,
|
||||
visualizado: false,
|
||||
},
|
||||
})
|
||||
novasDoProcesso++
|
||||
stats.totalPublicacoes++
|
||||
}
|
||||
}
|
||||
|
||||
if (novasDoProcesso > 0) {
|
||||
stats.processosComNovas++
|
||||
console.log(` ✅ ${processo.numeroProcesso}: ${novasDoProcesso} nova(s) publicação(ões)`)
|
||||
} else {
|
||||
console.log(` ➖ ${processo.numeroProcesso}: sem novas publicações`)
|
||||
}
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
const msg = error instanceof Error ? error.message : 'Erro desconhecido'
|
||||
stats.erros.push(`Erro geral: ${msg}`)
|
||||
console.error('\n❌ Erro durante execução:', error)
|
||||
} finally {
|
||||
await prisma.$disconnect()
|
||||
}
|
||||
|
||||
stats.fimEm = new Date()
|
||||
|
||||
// Resumo final
|
||||
console.log('\n' + '='.repeat(60))
|
||||
console.log('📊 RESUMO DA BUSCA')
|
||||
console.log('='.repeat(60))
|
||||
console.log(`Processos verificados: ${stats.totalProcessos}`)
|
||||
console.log(`Processos com novas publicações: ${stats.processosComNovas}`)
|
||||
console.log(`Total de novas publicações: ${stats.totalPublicacoes}`)
|
||||
console.log(`Erros: ${stats.erros.length}`)
|
||||
|
||||
if (stats.erros.length > 0) {
|
||||
console.log('\n⚠️ Erros encontrados:')
|
||||
stats.erros.forEach(e => console.log(` - ${e}`))
|
||||
}
|
||||
|
||||
const duracao = ((stats.fimEm.getTime() - stats.inicioEm.getTime()) / 1000).toFixed(1)
|
||||
console.log(`\n⏱️ Tempo de execução: ${duracao}s`)
|
||||
console.log(`[${stats.fimEm.toISOString()}] Busca finalizada\n`)
|
||||
|
||||
return stats
|
||||
}
|
||||
|
||||
// Executar
|
||||
buscarPublicacoesDiarias()
|
||||
.then(stats => {
|
||||
process.exit(stats.erros.length > 0 ? 1 : 0)
|
||||
})
|
||||
.catch(error => {
|
||||
console.error('Erro fatal:', error)
|
||||
process.exit(1)
|
||||
})
|
||||
36
scripts/setup-stripe.ts
Normal file
36
scripts/setup-stripe.ts
Normal file
@@ -0,0 +1,36 @@
|
||||
import Stripe from 'stripe'
|
||||
|
||||
const stripe = new Stripe(process.env.STRIPE_SECRET_KEY!, {
|
||||
apiVersion: '2025-04-30.basil' as any,
|
||||
})
|
||||
|
||||
const plans = [
|
||||
{ name: 'Teste', amount: 1, interval: 'month' as const },
|
||||
{ name: 'Starter', amount: 9700, interval: 'month' as const },
|
||||
{ name: 'Pro', amount: 19700, interval: 'month' as const },
|
||||
{ name: 'Enterprise', amount: 49700, interval: 'month' as const },
|
||||
]
|
||||
|
||||
async function main() {
|
||||
console.log('Creating Stripe products and prices...\n')
|
||||
|
||||
for (const plan of plans) {
|
||||
const product = await stripe.products.create({
|
||||
name: `LexMind ${plan.name}`,
|
||||
description: `Plano ${plan.name} - LexMind`,
|
||||
})
|
||||
|
||||
const price = await stripe.prices.create({
|
||||
product: product.id,
|
||||
unit_amount: plan.amount,
|
||||
currency: 'brl',
|
||||
recurring: { interval: plan.interval },
|
||||
})
|
||||
|
||||
console.log(`${plan.name}: product=${product.id} price=${price.id} (R$${(plan.amount / 100).toFixed(2)}/month)`)
|
||||
}
|
||||
|
||||
console.log('\nDone! Copy the price IDs above into your code.')
|
||||
}
|
||||
|
||||
main().catch(console.error)
|
||||
102
scripts/testar-datajud.ts
Normal file
102
scripts/testar-datajud.ts
Normal file
@@ -0,0 +1,102 @@
|
||||
#!/usr/bin/env npx ts-node
|
||||
|
||||
/**
|
||||
* Script de Teste da API DataJud
|
||||
* Testa a conexão e busca um processo de exemplo
|
||||
*/
|
||||
|
||||
// API Key pública do DataJud (CNJ)
|
||||
const DATAJUD_API_KEY = 'cDZHYzlZa0JadVREZDJCendQbXY6SkJlTzNjLV9TRENyQk1RdnFKZGRQdw=='
|
||||
const DATAJUD_BASE_URL = 'https://api-publica.datajud.cnj.jus.br'
|
||||
|
||||
async function testarDataJud() {
|
||||
console.log('='.repeat(60))
|
||||
console.log('🧪 Testando conexão com API DataJud (CNJ)')
|
||||
console.log('='.repeat(60))
|
||||
|
||||
// Teste 1: Buscar um processo aleatório
|
||||
console.log('\n1. Buscando processo de exemplo no TJSP...')
|
||||
|
||||
const url = `${DATAJUD_BASE_URL}/api_publica_tjsp/_search`
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `APIKey ${DATAJUD_API_KEY}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
size: 1,
|
||||
query: {
|
||||
bool: {
|
||||
must: [
|
||||
{ exists: { field: 'movimentos' } }
|
||||
],
|
||||
filter: [
|
||||
{ range: { '@timestamp': { gte: 'now-7d' } } }
|
||||
]
|
||||
}
|
||||
}
|
||||
}),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
console.log(`❌ Erro HTTP: ${response.status}`)
|
||||
const text = await response.text()
|
||||
console.log(text.substring(0, 500))
|
||||
return
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
console.log(`✅ Resposta OK - ${data.hits?.total?.value || 0} processos no índice`)
|
||||
|
||||
if (data.hits?.hits?.length > 0) {
|
||||
const processo = data.hits.hits[0]._source
|
||||
console.log(`\n📄 Processo encontrado:`)
|
||||
console.log(` Número: ${processo.numeroProcesso}`)
|
||||
console.log(` Classe: ${processo.classe?.nome || 'N/A'}`)
|
||||
console.log(` Tribunal: ${processo.tribunal}`)
|
||||
console.log(` Movimentos: ${processo.movimentos?.length || 0}`)
|
||||
|
||||
// Mostrar últimos movimentos
|
||||
const ultimos = (processo.movimentos || []).slice(-5)
|
||||
console.log('\n Últimos movimentos:')
|
||||
ultimos.forEach((m: any) => {
|
||||
console.log(` - ${m.dataHora?.substring(0, 10)} | ${m.nome} (código: ${m.codigo})`)
|
||||
})
|
||||
}
|
||||
|
||||
// Teste 2: Buscar processo específico (se existir)
|
||||
console.log('\n\n2. Testando busca por número específico...')
|
||||
|
||||
const response2 = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `APIKey ${DATAJUD_API_KEY}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
size: 1,
|
||||
query: {
|
||||
match: {
|
||||
numeroProcesso: '10000000020248260100' // Exemplo fictício
|
||||
}
|
||||
}
|
||||
}),
|
||||
})
|
||||
|
||||
const data2 = await response2.json()
|
||||
const found = data2.hits?.hits?.length > 0
|
||||
console.log(` Processo de teste: ${found ? '✅ Encontrado' : '➖ Não encontrado (esperado)'}`)
|
||||
|
||||
console.log('\n' + '='.repeat(60))
|
||||
console.log('✅ API DataJud funcionando corretamente!')
|
||||
console.log('='.repeat(60))
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro ao conectar:', error)
|
||||
}
|
||||
}
|
||||
|
||||
testarDataJud()
|
||||
64
scripts/teste-integracao.ts
Normal file
64
scripts/teste-integracao.ts
Normal file
@@ -0,0 +1,64 @@
|
||||
#!/usr/bin/env npx ts-node
|
||||
|
||||
/**
|
||||
* Teste de Integração Completa
|
||||
* Testa buscarPublicacoesReais com um número de processo real
|
||||
*/
|
||||
|
||||
import { buscarPublicacoesReais, buscarDataJud } from '../src/lib/diarios-service'
|
||||
|
||||
async function testarIntegracao() {
|
||||
console.log('='.repeat(60))
|
||||
console.log('🧪 Teste de Integração - Busca de Publicações')
|
||||
console.log('='.repeat(60))
|
||||
|
||||
// Processo de teste (usando um real do TJSP que sabemos existir)
|
||||
const processoTeste = {
|
||||
id: 'teste-001',
|
||||
numeroProcesso: '1000044-50.2025.8.26.0220',
|
||||
tribunal: 'TJSP',
|
||||
}
|
||||
|
||||
console.log(`\n📋 Processo de teste:`)
|
||||
console.log(` Número: ${processoTeste.numeroProcesso}`)
|
||||
console.log(` Tribunal: ${processoTeste.tribunal}`)
|
||||
|
||||
console.log('\n🔍 Buscando publicações...\n')
|
||||
|
||||
try {
|
||||
const resultado = await buscarPublicacoesReais(processoTeste, 365) // Últimos 365 dias
|
||||
|
||||
console.log(`✅ Busca concluída!`)
|
||||
console.log(` Sucesso: ${resultado.sucesso}`)
|
||||
console.log(` Fonte: ${resultado.fonte}`)
|
||||
console.log(` Publicações encontradas: ${resultado.publicacoes.length}`)
|
||||
|
||||
if (resultado.erro) {
|
||||
console.log(` Erro: ${resultado.erro}`)
|
||||
}
|
||||
|
||||
if (resultado.publicacoes.length > 0) {
|
||||
console.log('\n📰 Publicações encontradas:')
|
||||
resultado.publicacoes.slice(0, 10).forEach((pub, i) => {
|
||||
console.log(`\n ${i + 1}. ${pub.tipo}`)
|
||||
console.log(` Data: ${pub.dataPublicacao.toISOString().split('T')[0]}`)
|
||||
console.log(` Prazo: ${pub.prazoCalculado?.toISOString().split('T')[0]} (${pub.prazoTipo})`)
|
||||
console.log(` Conteúdo: ${pub.conteudo.substring(0, 100)}...`)
|
||||
})
|
||||
}
|
||||
|
||||
// Testar também busca direta no DataJud
|
||||
console.log('\n\n🔬 Testando busca direta DataJud (processo diferente)...')
|
||||
const resultado2 = await buscarDataJud('0020077-82.2022.8.26.0576', 'TJSP')
|
||||
console.log(` Publicações: ${resultado2.publicacoes.length}`)
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro:', error)
|
||||
}
|
||||
|
||||
console.log('\n' + '='.repeat(60))
|
||||
console.log('✅ Teste de integração finalizado')
|
||||
console.log('='.repeat(60))
|
||||
}
|
||||
|
||||
testarIntegracao()
|
||||
84
scripts/teste-standalone.ts
Normal file
84
scripts/teste-standalone.ts
Normal file
@@ -0,0 +1,84 @@
|
||||
#!/usr/bin/env npx ts-node
|
||||
|
||||
/**
|
||||
* Teste Standalone da API DataJud
|
||||
* Não depende de imports externos
|
||||
*/
|
||||
|
||||
const DATAJUD_API_KEY = 'cDZHYzlZa0JadVREZDJCendQbXY6SkJlTzNjLV9TRENyQk1RdnFKZGRQdw=='
|
||||
|
||||
interface Movimento {
|
||||
codigo: number
|
||||
nome: string
|
||||
dataHora: string
|
||||
orgaoJulgador?: { nome: string }
|
||||
complementosTabelados?: Array<{ nome: string }>
|
||||
}
|
||||
|
||||
async function buscarDataJud(numeroProcesso: string, tribunal: string) {
|
||||
const endpoint = `api_publica_${tribunal.toLowerCase()}`
|
||||
const url = `https://api-publica.datajud.cnj.jus.br/${endpoint}/_search`
|
||||
const numeroLimpo = numeroProcesso.replace(/\D/g, '')
|
||||
|
||||
const response = await fetch(url, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `APIKey ${DATAJUD_API_KEY}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
size: 1,
|
||||
query: { match: { numeroProcesso: numeroLimpo } },
|
||||
}),
|
||||
})
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${await response.text()}`)
|
||||
}
|
||||
|
||||
return await response.json()
|
||||
}
|
||||
|
||||
async function main() {
|
||||
console.log('='.repeat(60))
|
||||
console.log('🧪 Teste Standalone - API DataJud')
|
||||
console.log('='.repeat(60))
|
||||
|
||||
// Teste com processo que encontramos antes
|
||||
const processoNumero = '1000044-50.2025.8.26.0220'
|
||||
console.log(`\n📋 Buscando: ${processoNumero}`)
|
||||
|
||||
try {
|
||||
const data = await buscarDataJud(processoNumero, 'TJSP')
|
||||
const hits = data.hits?.hits || []
|
||||
|
||||
if (hits.length === 0) {
|
||||
console.log('❌ Processo não encontrado')
|
||||
return
|
||||
}
|
||||
|
||||
const processo = hits[0]._source
|
||||
console.log(`\n✅ Processo encontrado!`)
|
||||
console.log(` Classe: ${processo.classe?.nome}`)
|
||||
console.log(` Órgão: ${processo.orgaoJulgador?.nome}`)
|
||||
console.log(` Total movimentos: ${processo.movimentos?.length || 0}`)
|
||||
|
||||
// Filtrar publicações
|
||||
const publicacoes = (processo.movimentos || []).filter((m: Movimento) =>
|
||||
m.codigo === 92 || // Publicação
|
||||
m.nome?.toLowerCase().includes('publicação') ||
|
||||
m.nome?.toLowerCase().includes('intimação') ||
|
||||
m.nome?.toLowerCase().includes('citação')
|
||||
)
|
||||
|
||||
console.log(`\n📰 Publicações/Intimações (${publicacoes.length}):`)
|
||||
publicacoes.slice(0, 10).forEach((m: Movimento, i: number) => {
|
||||
console.log(` ${i + 1}. ${m.dataHora?.substring(0, 10)} | ${m.nome}`)
|
||||
})
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Erro:', error)
|
||||
}
|
||||
}
|
||||
|
||||
main()
|
||||
Reference in New Issue
Block a user