datajud 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0322247203376f73cf7f797183970f8ef7d7147e4bd782c09d8494b255104668
4
- data.tar.gz: 8533fd1daf5c4ce9e9e4c6771ff07e32435a976c6bfab9b069aa8fd591012437
3
+ metadata.gz: 5f39081aadf1eae3fd48ec2b4c41290747c9c1d7af57e1c2277a030633ed9e64
4
+ data.tar.gz: aab5ae80ec67d1465641b0af7b4674b1ee2dceddcc20c5ef36fbf9263dd2a23a
5
5
  SHA512:
6
- metadata.gz: c460a3f2464dd88e681bd86255948af4adb184b7006901f96e24ffabb3bd3083d07ee86492f3d259a2cc62d89687960bd318d271a97a2ba5c86aa423db729884
7
- data.tar.gz: 8835e83491188e7d35864ae9c132f418fe4f1cd2d80528d9d587b1527d92bd5bdc348924ab3d59c626246e8b4bb6b5f5f5bbc41dd4d651ee7adc955f6025a879
6
+ metadata.gz: 8c0c96e126baf36e5a1e9fe6960a60f6bf332290931515f8386245c4e808905a89c2bae3a89dd38fb900a6de953739e9175edc2880047520d62ae054bab7c674
7
+ data.tar.gz: f518b69601b88db2d9a7eb452673019449504772ce4d818e2c64d65e663b8b72a1f8ec1910ce37a5839cd135b1d65386f43ba9fe67dd72b731484212cf267d53
data/CHANGELOG.md CHANGED
@@ -1,5 +1,9 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.1.2] - 2026-03-12
4
+
5
+ - Added `Datajud.find` to return process data via an object-oriented API.
6
+
3
7
  ## [0.1.0] - 2025-11-25
4
8
 
5
9
  - Initial release
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- datajud (0.1.0)
4
+ datajud (0.1.3)
5
5
  json (~> 2.0)
6
6
  net-http (~> 0.3)
7
7
  nokogiri (~> 1.14)
data/README.md CHANGED
@@ -1,8 +1,6 @@
1
1
  # Datajud
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/datajud`. To experiment with that code, run `bin/console` for an interactive prompt.
4
-
5
- TODO: Delete this and the text above, and describe your gem
3
+ SDK simples para consumir a API pública do DataJud (CNJ) em Ruby.
6
4
 
7
5
  ## Installation
8
6
 
@@ -16,7 +14,143 @@ If bundler is not being used to manage dependencies, install the gem by executin
16
14
 
17
15
  ## Usage
18
16
 
19
- TODO: Write usage instructions here
17
+ ### Consultar processo com API orientada a objeto
18
+
19
+ ```ruby
20
+ require 'datajud'
21
+
22
+ processo = Datajud.find("00008323520184013202")
23
+
24
+ # Com tribunal explícito
25
+ processo = Datajud.find("00008323520184013202", tribunal: "trf1")
26
+
27
+ processo.numero
28
+ processo.classe
29
+ processo.partes
30
+ processo.movimentacoes
31
+
32
+ # Tribunal como objeto
33
+ processo.tribunal
34
+ # => { nome: "TRF1", sigla: "TRF1", esfera: "Federal" }
35
+
36
+ # Tabela HTML de endpoints (todos os tribunais conhecidos)
37
+ Datajud.endpoints_table(Datajud::TRIBUNAIS_SIGLAS)
38
+ ```
39
+
40
+ ### Métodos de consulta disponíveis
41
+
42
+ ```ruby
43
+ # API orientada a objeto
44
+ processo = Datajud.find("00008323520184013202", tribunal: "trf1")
45
+
46
+ # Retorno bruto (hash)
47
+ resultado = Datajud.processo("00008323520184013202", tribunal: "trf1")
48
+
49
+ # Consulta genérica com filtros (Elasticsearch)
50
+ resultado = Datajud::ApiClient.buscar("trf1", match: { numeroProcesso: "00008323520184013202" })
51
+
52
+ # Atalho para buscar processo (modo legado)
53
+ resultado = Datajud::ApiClient.buscar_processo("00008323520184013202", "trf1")
54
+ ```
55
+
56
+ > Dica: quando quiser ver todas as chaves retornadas pela API, prefira `Datajud.processo`.
57
+
58
+ ### Compatibilidade com ApiClient (modo legado)
59
+
60
+ ```ruby
61
+ Datajud.configure do |config|
62
+ config.api_key = "SUA_API_KEY"
63
+ end
64
+
65
+ resultado = DataJud::ApiClient.buscar_processo("00008323520184013202", "trf1")
66
+ puts resultado
67
+ ```
68
+
69
+ ### Auto-detectar tribunal pelo número CNJ
70
+
71
+ Se o número estiver no formato CNJ, a gem tenta derivar o tribunal automaticamente
72
+ para evitar varrer todas as bases.
73
+
74
+ ```ruby
75
+ processo = Datajud.find("0000832-35.2018.8.26.0202")
76
+ puts processo.tribunal
77
+ ```
78
+
79
+ > A UF da comarca é derivada localmente pelo código IBGE do município quando disponível.
80
+
81
+ ### Configuração (API key, timeout e retries)
82
+
83
+ ```ruby
84
+ Datajud.configure do |config|
85
+ config.api_key = "SUA_API_KEY"
86
+ config.open_timeout = 5
87
+ config.read_timeout = 15
88
+ config.retries = 2
89
+ config.retry_wait = 0.5
90
+ config.fallback_all_on_miss = true
91
+ config.lookup_ibge = true
92
+ config.ibge_base_url = "https://servicodados.ibge.gov.br/api/v1/localidades/municipios"
93
+ end
94
+ ```
95
+
96
+ Ou via variável de ambiente:
97
+
98
+ ```bash
99
+ export DATAJUD_API_KEY="SUA_API_KEY"
100
+ ```
101
+
102
+ ### Consultar processo sem passar tribunal
103
+
104
+ ```ruby
105
+ require 'datajud'
106
+
107
+ resultado = Datajud.processo("00008323520184013202")
108
+ puts resultado
109
+ ```
110
+
111
+ ### Consultar processo passando 1 tribunal
112
+
113
+ ```ruby
114
+ require 'datajud'
115
+
116
+ resultado = Datajud.processo("00008323520184013202", tribunal: "trf1")
117
+ puts resultado
118
+ ```
119
+
120
+ ### Consultar processo passando vários tribunais
121
+
122
+ ```ruby
123
+ require 'datajud'
124
+
125
+ resultado = Datajud.processo("00008323520184013202", tribunal: ["trf1", "tjmg"])
126
+ puts resultado
127
+ ```
128
+
129
+ ### Listas de tribunais disponíveis
130
+
131
+ Você pode acessar as listas de siglas dos tribunais diretamente pelas constantes do módulo:
132
+
133
+ ```ruby
134
+ require 'datajud'
135
+
136
+ # Todos os tribunais
137
+ Datajud::TRIBUNAIS_SIGLAS
138
+
139
+ # Apenas TJs
140
+ Datajud::TJS_SIGLAS
141
+
142
+ # Apenas TRFs
143
+ Datajud::TRFS_SIGLAS
144
+
145
+ # Apenas TRTs
146
+ Datajud::TRTS_SIGLAS
147
+
148
+ # Apenas TREs
149
+ Datajud::TRES_SIGLAS
150
+
151
+ # Apenas Superiores
152
+ Datajud::SUPERIORES_SIGLAS
153
+ ```
20
154
 
21
155
  ## Development
22
156
 
@@ -26,7 +160,7 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
26
160
 
27
161
  ## Contributing
28
162
 
29
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/datajud. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/[USERNAME]/datajud/blob/master/CODE_OF_CONDUCT.md).
163
+ Bug reports and pull requests are welcome on GitHub at https://github.com/PablUoo/datajud. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [code of conduct](https://github.com/PablUoo/datajud/blob/master/CODE_OF_CONDUCT.md).
30
164
 
31
165
  ## License
32
166
 
@@ -34,4 +168,4 @@ The gem is available as open source under the terms of the [MIT License](https:/
34
168
 
35
169
  ## Code of Conduct
36
170
 
37
- Everyone interacting in the Datajud project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/datajud/blob/master/CODE_OF_CONDUCT.md).
171
+ Everyone interacting in the Datajud project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/PablUoo/datajud/blob/master/CODE_OF_CONDUCT.md).
data/examples/find.rb ADDED
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../lib/datajud"
4
+
5
+ Datajud.configure do |config|
6
+ config.open_timeout = 3
7
+ config.read_timeout = 5
8
+ end
9
+
10
+ begin
11
+ processo = Datajud.find("0000832-35.2018.8.26.0202")
12
+
13
+ if processo
14
+ puts "Tribunal: #{processo.tribunal}"
15
+ puts "Número: #{processo.numero}"
16
+ puts "Classe: #{processo.classe}"
17
+ puts "Partes: #{processo.partes.map(&:nome).join(', ')}"
18
+ puts "Movimentações: #{processo.movimentacoes.size}"
19
+ else
20
+ puts "Processo não encontrado."
21
+ end
22
+ rescue StandardError => e
23
+ warn "Erro ao consultar DataJud: #{e.class} - #{e.message}"
24
+ end
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'net/http'
4
+ require 'json'
5
+
6
+ module Datajud
7
+ class ApiClient
8
+ BASE_URL = "https://api-publica.datajud.cnj.jus.br"
9
+
10
+ # Consulta genérica: tribunal e filtros customizados
11
+ def self.buscar(tribunal, filtros = {})
12
+ endpoint = "/api_publica_#{tribunal.downcase}/_search"
13
+ url = URI("#{Datajud.configuration.base_endpoint}#{endpoint}")
14
+ http = Net::HTTP.new(url.host, url.port)
15
+ http.use_ssl = (url.scheme == "https")
16
+ http.open_timeout = Datajud.configuration.open_timeout
17
+ http.read_timeout = Datajud.configuration.read_timeout
18
+
19
+ request = Net::HTTP::Post.new(url)
20
+ request['Authorization'] = "APIKey #{Datajud.api_key}"
21
+ request['Content-Type'] = 'application/json'
22
+ request.body = { query: filtros }.to_json
23
+
24
+ begin
25
+ response = Datajud.request_with_retry(http, request)
26
+ if response.is_a?(Net::HTTPSuccess)
27
+ JSON.parse(response.body)
28
+ else
29
+ { error: response.message, status: response.code, body: response.body }
30
+ end
31
+ rescue SocketError => e
32
+ { error: "Falha de conexão: #{e.message}" }
33
+ rescue Errno::ECONNRESET => e
34
+ { error: "Conexão resetada pelo servidor: #{e.message}" }
35
+ rescue EOFError => e
36
+ { error: "Resposta inesperada da API: #{e.message}" }
37
+ rescue StandardError => e
38
+ { error: "Erro desconhecido: #{e.message}" }
39
+ end
40
+ end
41
+
42
+ # Busca por número de processo (atalho)
43
+ def self.buscar_processo(numero_processo, tribunal)
44
+ filtros = { match: { numeroProcesso: numero_processo } }
45
+ buscar(tribunal, filtros)
46
+ end
47
+ end
48
+ end
49
+
50
+ # Alias para compatibilidade com código legado
51
+ module DataJud
52
+ ApiClient = Datajud::ApiClient
53
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datajud
4
+ class Client
5
+ # Retorna uma instância de Datajud::Processo ou nil
6
+ def self.find(numero, tribunal = nil, **kwargs)
7
+ tribunal = kwargs[:tribunal] if tribunal.nil? && kwargs.key?(:tribunal)
8
+ raw = Datajud.processo(numero, tribunal: tribunal)
9
+ return nil unless raw && raw[:processo] || raw && raw['processo']
10
+
11
+ Datajud::Processo.new(raw)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datajud
4
+ # Configurações da gem.
5
+ class Configuration
6
+ attr_accessor :base_endpoint, :tribunais, :api_key, :open_timeout, :read_timeout,
7
+ :retries, :retry_wait, :fallback_all_on_miss, :lookup_ibge, :ibge_base_url
8
+
9
+ def initialize
10
+ @base_endpoint = "https://api-publica.datajud.cnj.jus.br"
11
+ @tribunais = []
12
+ @api_key = nil
13
+ @open_timeout = 5
14
+ @read_timeout = 15
15
+ @retries = 1
16
+ @retry_wait = 0.3
17
+ @fallback_all_on_miss = true
18
+ @lookup_ibge = true
19
+ @ibge_base_url = "https://servicodados.ibge.gov.br/api/v1/localidades/municipios"
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'ostruct'
4
+
5
+ module Datajud
6
+ # Representa um processo retornado pela API DataJud.
7
+ # Fornece acesso simples a campos comuns via métodos.
8
+ class Processo
9
+ attr_reader :tribunal, :data
10
+
11
+ def initialize(raw)
12
+ # raw expected: { tribunal: 'TJSP', processo: { ... } } or string-keyed
13
+ @tribunal = raw[:tribunal] || raw['tribunal']
14
+ @data = raw[:processo] || raw['processo'] || {}
15
+ end
16
+
17
+ def numero
18
+ @data['numero'] || @data[:numero]
19
+ end
20
+
21
+ def classe
22
+ @data['classe'] || @data[:classe]
23
+ end
24
+
25
+ def vara
26
+ v = @data['vara'] || @data[:vara]
27
+ return nil unless v
28
+
29
+ OpenStruct.new(
30
+ nome: v['nome'] || v[:nome],
31
+ codigo: v['codigo'] || v[:codigo],
32
+ comarca: v['comarca'] || v[:comarca]
33
+ )
34
+ end
35
+
36
+ def situacao
37
+ @data['situacao'] || @data[:situacao]
38
+ end
39
+
40
+ def origem
41
+ @data['origem'] || @data[:origem]
42
+ end
43
+
44
+ def instancia
45
+ @data['instancia'] || @data[:instancia]
46
+ end
47
+
48
+ def assunto
49
+ @data['assunto'] || @data[:assunto]
50
+ end
51
+
52
+ def partes
53
+ partes = @data['partes'] || @data[:partes] || []
54
+ partes.map do |p|
55
+ OpenStruct.new(
56
+ nome: p['nome'] || p[:nome],
57
+ tipo: p['tipo'] || p['tipoParte'] || p[:tipo],
58
+ documento: p['documento'] || p[:documento]
59
+ )
60
+ end
61
+ end
62
+
63
+ def andamentos
64
+ mov = @data['andamentos'] || @data[:andamentos] || @data['movimentacoes'] || @data[:movimentacoes]
65
+ (mov || []).map do |m|
66
+ OpenStruct.new(
67
+ descricao: m['descricao'] || m[:descricao],
68
+ data: m['data'] || m['dataHora'] || m[:data],
69
+ tipo: m['tipo'] || m['codigoTipoMovimento'] || m[:tipo]
70
+ )
71
+ end
72
+ end
73
+
74
+ def documentos
75
+ docs = @data['documentos'] || @data[:documentos] || []
76
+ docs.map do |d|
77
+ OpenStruct.new(
78
+ titulo: d['titulo'] || d['nomeDocumento'] || d[:titulo],
79
+ tipo: d['tipo'] || d['tipoDocumento'] || d[:tipo],
80
+ data: d['data'] || d['dataJuntada'] || d[:data],
81
+ assinatura_digital: d['assinatura_digital'] || d['assinaturaDigital'] || d[:assinatura_digital]
82
+ )
83
+ end
84
+ end
85
+
86
+ def audiencias
87
+ auds = @data['audiencias'] || @data[:audiencias] || []
88
+ auds.map do |a|
89
+ OpenStruct.new(
90
+ data_hora: a['data_hora'] || a['dataHora'] || a[:data_hora],
91
+ tipo: a['tipo'] || a[:tipo],
92
+ status: a['status'] || a['statusAudiencia'] || a[:status],
93
+ observacao: a['observacao'] || a[:observacao]
94
+ )
95
+ end
96
+ end
97
+
98
+ alias movimentacoes andamentos
99
+
100
+ def to_h
101
+ { tribunal: tribunal, processo: data }
102
+ end
103
+ end
104
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Datajud
4
- VERSION = "0.1.1"
4
+ VERSION = "0.1.3"
5
5
  end
data/lib/datajud.rb CHANGED
@@ -1,10 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'socket'
3
4
  require_relative "datajud/version"
4
5
  require_relative "datajud/key_fetcher"
6
+ require_relative "datajud/configuration"
7
+ require_relative "datajud/api_client"
8
+ require_relative "datajud/client"
9
+ require_relative "datajud/process"
5
10
  require 'net/http'
6
11
  require 'json'
7
12
 
13
+ unless Socket.method(:tcp).parameters.any? { |param| param[1] == :open_timeout }
14
+ class << Socket
15
+ alias_method :tcp_without_open_timeout, :tcp
16
+
17
+ def tcp(host, port, local_host = nil, local_port = nil, **kwargs)
18
+ if kwargs.key?(:open_timeout) && !kwargs.key?(:connect_timeout)
19
+ kwargs[:connect_timeout] = kwargs.delete(:open_timeout)
20
+ end
21
+
22
+ tcp_without_open_timeout(host, port, local_host, local_port, **kwargs)
23
+ end
24
+ end
25
+ end
26
+
8
27
  module Datajud
9
28
  BASE_ENDPT = "https://api-publica.datajud.cnj.jus.br"
10
29
  # Tribunais de Justiça Estaduais (TJs)
@@ -16,7 +35,7 @@ module Datajud
16
35
 
17
36
  # Tribunais Regionais Federais (TRFs)
18
37
  TRFS_SIGLAS = [
19
- "trf1", "trf2", "trf3", "trf4", "trf5"
38
+ "trf1", "trf2", "trf3", "trf4", "trf5", "trf6"
20
39
  ]
21
40
 
22
41
  # Tribunais Regionais do Trabalho (TRTs)
@@ -39,11 +58,229 @@ module Datajud
39
58
  "tse", "stf", "stj", "stm", "tst"
40
59
  ]
41
60
 
61
+ TJM_SIGLAS = [
62
+ "tjmsp", "tjmrs", "tjmmg"
63
+ ]
64
+
65
+ SUPERIORES_NOMES = {
66
+ "tst" => "Tribunal Superior do Trabalho",
67
+ "tse" => "Tribunal Superior Eleitoral",
68
+ "stj" => "Tribunal Superior de Justiça",
69
+ "stm" => "Tribunal Superior Militar",
70
+ "stf" => "Supremo Tribunal Federal"
71
+ }.freeze
72
+
73
+ TRIBUNAL_NOMES = SUPERIORES_NOMES.merge(
74
+ "trf1" => "Tribunal Regional Federal da 1ª Região",
75
+ "trf2" => "Tribunal Regional Federal da 2ª Região",
76
+ "trf3" => "Tribunal Regional Federal da 3ª Região",
77
+ "trf4" => "Tribunal Regional Federal da 4ª Região",
78
+ "trf5" => "Tribunal Regional Federal da 5ª Região",
79
+ "trf6" => "Tribunal Regional Federal da 6ª Região",
80
+ "tjac" => "Tribunal de Justiça do Acre",
81
+ "tjal" => "Tribunal de Justiça de Alagoas",
82
+ "tjam" => "Tribunal de Justiça do Amazonas",
83
+ "tjap" => "Tribunal de Justiça do Amapá",
84
+ "tjba" => "Tribunal de Justiça da Bahia",
85
+ "tjce" => "Tribunal de Justiça do Ceará",
86
+ "tjdft" => "Tribunal de Justiça do Distrito Federal e Territórios",
87
+ "tjdf" => "Tribunal de Justiça do Distrito Federal e Territórios",
88
+ "tjes" => "Tribunal de Justiça do Espírito Santo",
89
+ "tjgo" => "Tribunal de Justiça de Goiás",
90
+ "tjma" => "Tribunal de Justiça do Maranhão",
91
+ "tjmg" => "Tribunal de Justiça de Minas Gerais",
92
+ "tjms" => "Tribunal de Justiça de Mato Grosso do Sul",
93
+ "tjmt" => "Tribunal de Justiça do Mato Grosso",
94
+ "tjpa" => "Tribunal de Justiça do Pará",
95
+ "tjpb" => "Tribunal de Justiça da Paraíba",
96
+ "tjpe" => "Tribunal de Justiça de Pernambuco",
97
+ "tjpi" => "Tribunal de Justiça do Piauí",
98
+ "tjpr" => "Tribunal de Justiça do Paraná",
99
+ "tjrj" => "Tribunal de Justiça do Rio de Janeiro",
100
+ "tjrn" => "Tribunal de Justiça do Rio Grande do Norte",
101
+ "tjro" => "Tribunal de Justiça de Rondônia",
102
+ "tjrr" => "Tribunal de Justiça de Roraima",
103
+ "tjrs" => "Tribunal de Justiça do Rio Grande do Sul",
104
+ "tjsc" => "Tribunal de Justiça de Santa Catarina",
105
+ "tjse" => "Tribunal de Justiça de Sergipe",
106
+ "tjsp" => "Tribunal de Justiça de São Paulo",
107
+ "tjto" => "Tribunal de Justiça do Tocantins",
108
+ "trt1" => "Tribunal Regional do Trabalho da 1ª Região",
109
+ "trt2" => "Tribunal Regional do Trabalho da 2ª Região",
110
+ "trt3" => "Tribunal Regional do Trabalho da 3ª Região",
111
+ "trt4" => "Tribunal Regional do Trabalho da 4ª Região",
112
+ "trt5" => "Tribunal Regional do Trabalho da 5ª Região",
113
+ "trt6" => "Tribunal Regional do Trabalho da 6ª Região",
114
+ "trt7" => "Tribunal Regional do Trabalho da 7ª Região",
115
+ "trt8" => "Tribunal Regional do Trabalho da 8ª Região",
116
+ "trt9" => "Tribunal Regional do Trabalho da 9ª Região",
117
+ "trt10" => "Tribunal Regional do Trabalho da 10ª Região",
118
+ "trt11" => "Tribunal Regional do Trabalho da 11ª Região",
119
+ "trt12" => "Tribunal Regional do Trabalho da 12ª Região",
120
+ "trt13" => "Tribunal Regional do Trabalho da 13ª Região",
121
+ "trt14" => "Tribunal Regional do Trabalho da 14ª Região",
122
+ "trt15" => "Tribunal Regional do Trabalho da 15ª Região",
123
+ "trt16" => "Tribunal Regional do Trabalho da 16ª Região",
124
+ "trt17" => "Tribunal Regional do Trabalho da 17ª Região",
125
+ "trt18" => "Tribunal Regional do Trabalho da 18ª Região",
126
+ "trt19" => "Tribunal Regional do Trabalho da 19ª Região",
127
+ "trt20" => "Tribunal Regional do Trabalho da 20ª Região",
128
+ "trt21" => "Tribunal Regional do Trabalho da 21ª Região",
129
+ "trt22" => "Tribunal Regional do Trabalho da 22ª Região",
130
+ "trt23" => "Tribunal Regional do Trabalho da 23ª Região",
131
+ "trt24" => "Tribunal Regional do Trabalho da 24ª Região",
132
+ "treac" => "Tribunal Regional Eleitoral do Acre",
133
+ "treal" => "Tribunal Regional Eleitoral de Alagoas",
134
+ "tream" => "Tribunal Regional Eleitoral do Amazonas",
135
+ "treap" => "Tribunal Regional Eleitoral do Amapá",
136
+ "treba" => "Tribunal Regional Eleitoral da Bahia",
137
+ "trece" => "Tribunal Regional Eleitoral do Ceará",
138
+ "tredf" => "Tribunal Regional Eleitoral do Distrito Federal",
139
+ "trees" => "Tribunal Regional Eleitoral do Espírito Santo",
140
+ "trego" => "Tribunal Regional Eleitoral de Goiás",
141
+ "trema" => "Tribunal Regional Eleitoral do Maranhão",
142
+ "tremg" => "Tribunal Regional Eleitoral de Minas Gerais",
143
+ "trems" => "Tribunal Regional Eleitoral do Mato Grosso do Sul",
144
+ "tremt" => "Tribunal Regional Eleitoral do Mato Grosso",
145
+ "trepa" => "Tribunal Regional Eleitoral do Pará",
146
+ "trepb" => "Tribunal Regional Eleitoral da Paraíba",
147
+ "trepe" => "Tribunal Regional Eleitoral de Pernambuco",
148
+ "trepi" => "Tribunal Regional Eleitoral do Piauí",
149
+ "trepr" => "Tribunal Regional Eleitoral do Paraná",
150
+ "trerj" => "Tribunal Regional Eleitoral do Rio de Janeiro",
151
+ "trern" => "Tribunal Regional Eleitoral do Rio Grande do Norte",
152
+ "trero" => "Tribunal Regional Eleitoral de Rondônia",
153
+ "trerr" => "Tribunal Regional Eleitoral de Roraima",
154
+ "trers" => "Tribunal Regional Eleitoral do Rio Grande do Sul",
155
+ "tresc" => "Tribunal Regional Eleitoral de Santa Catarina",
156
+ "trese" => "Tribunal Regional Eleitoral de Sergipe",
157
+ "tresp" => "Tribunal Regional Eleitoral de São Paulo",
158
+ "tretoc" => "Tribunal Regional Eleitoral do Tocantins",
159
+ "tjmsp" => "Tribunal de Justiça Militar de São Paulo",
160
+ "tjmrs" => "Tribunal de Justiça Militar do Rio Grande do Sul",
161
+ "tjmmg" => "Tribunal de Justiça Militar de Minas Gerais"
162
+ ).freeze
163
+
42
164
  # Para consultar em todos, você pode unificar todas as listas:
43
- TRIBUNAIS_SIGLAS = TJS_SIGLAS + TRFS_SIGLAS + TRTS_SIGLAS + TRES_SIGLAS + SUPERIORES_SIGLAS
165
+ TRIBUNAIS_SIGLAS = TJS_SIGLAS + TRFS_SIGLAS + TRTS_SIGLAS + TRES_SIGLAS + SUPERIORES_SIGLAS + TJM_SIGLAS
166
+
167
+ TJ_BY_CODE = {
168
+ "01" => "tjac",
169
+ "02" => "tjal",
170
+ "03" => "tjap",
171
+ "04" => "tjam",
172
+ "05" => "tjba",
173
+ "06" => "tjce",
174
+ "07" => "tjdf",
175
+ "08" => "tjes",
176
+ "09" => "tjgo",
177
+ "10" => "tjma",
178
+ "11" => "tjmt",
179
+ "12" => "tjms",
180
+ "13" => "tjmg",
181
+ "14" => "tjpa",
182
+ "15" => "tjpb",
183
+ "16" => "tjpr",
184
+ "17" => "tjpe",
185
+ "18" => "tjpi",
186
+ "19" => "tjrj",
187
+ "20" => "tjrn",
188
+ "21" => "tjrs",
189
+ "22" => "tjro",
190
+ "23" => "tjrr",
191
+ "24" => "tjsc",
192
+ "25" => "tjse",
193
+ "26" => "tjsp",
194
+ "27" => "to"
195
+ }.freeze
196
+
197
+ UF_BY_CODE = {
198
+ "01" => "ac",
199
+ "02" => "al",
200
+ "03" => "ap",
201
+ "04" => "am",
202
+ "05" => "ba",
203
+ "06" => "ce",
204
+ "07" => "df",
205
+ "08" => "es",
206
+ "09" => "go",
207
+ "10" => "ma",
208
+ "11" => "mt",
209
+ "12" => "ms",
210
+ "13" => "mg",
211
+ "14" => "pa",
212
+ "15" => "pb",
213
+ "16" => "pr",
214
+ "17" => "pe",
215
+ "18" => "pi",
216
+ "19" => "rj",
217
+ "20" => "rn",
218
+ "21" => "rs",
219
+ "22" => "ro",
220
+ "23" => "rr",
221
+ "24" => "sc",
222
+ "25" => "se",
223
+ "26" => "sp",
224
+ "27" => "to"
225
+ }.freeze
226
+
227
+ IBGE_UF_SIGLAS = {
228
+ "11" => "RO",
229
+ "12" => "AC",
230
+ "13" => "AM",
231
+ "14" => "RR",
232
+ "15" => "PA",
233
+ "16" => "AP",
234
+ "17" => "TO",
235
+ "21" => "MA",
236
+ "22" => "PI",
237
+ "23" => "CE",
238
+ "24" => "RN",
239
+ "25" => "PB",
240
+ "26" => "PE",
241
+ "27" => "AL",
242
+ "28" => "SE",
243
+ "29" => "BA",
244
+ "31" => "MG",
245
+ "32" => "ES",
246
+ "33" => "RJ",
247
+ "35" => "SP",
248
+ "41" => "PR",
249
+ "42" => "SC",
250
+ "43" => "RS",
251
+ "50" => "MS",
252
+ "51" => "MT",
253
+ "52" => "GO",
254
+ "53" => "DF"
255
+ }.freeze
256
+
257
+ ESFERA_BY_PREFIX = {
258
+ "TRF" => "Federal",
259
+ "TJ" => "Estadual",
260
+ "TRT" => "Trabalhista",
261
+ "TRE" => "Eleitoral",
262
+ "STF" => "Superior",
263
+ "STJ" => "Superior",
264
+ "TST" => "Superior",
265
+ "STM" => "Superior",
266
+ "TSE" => "Superior"
267
+ }.freeze
268
+
269
+ def self.configuration
270
+ @configuration ||= Configuration.new
271
+ end
272
+
273
+ def self.configure
274
+ yield(configuration)
275
+ end
44
276
 
45
277
  # Pega a API Key sempre atual (consulta ao site DataJud)
46
278
  def self.api_key
279
+ return configuration.api_key if configuration.api_key
280
+
281
+ env_key = ENV["DATAJUD_API_KEY"]
282
+ return env_key if env_key && !env_key.strip.empty?
283
+
47
284
  @api_key ||= KeyFetcher.fetch_api_key
48
285
  end
49
286
 
@@ -52,94 +289,227 @@ module Datajud
52
289
  @api_key = nil
53
290
  end
54
291
 
55
- def self.processo(numero, tribunal: nil)
56
- siglas_consulta = tribunal ? Array(tribunal).flatten.map { |t| t.to_s.downcase } : TRIBUNAIS_SIGLAS
292
+ def self.siglas_por_cnj(cnj)
293
+ digits = cnj.to_s.gsub(/\D/, "")
294
+ return nil unless digits.length == 20
295
+
296
+ j = digits[13]
297
+ tr = digits[14, 2]
298
+
299
+ case j
300
+ when "1"
301
+ tr_num = tr.to_i
302
+ return ["trf#{tr_num}"] if tr_num.between?(1, 5)
303
+ when "2"
304
+ sigla = TJ_BY_CODE[tr]
305
+ return [sigla] if sigla
306
+ when "3"
307
+ tr_num = tr.to_i
308
+ return ["trt#{tr_num}"] if tr_num.between?(1, 24)
309
+ when "4"
310
+ uf = UF_BY_CODE[tr]
311
+ return ["tre#{uf}"] if uf
312
+ when "5"
313
+ return ["stm"]
314
+ end
315
+
316
+ nil
317
+ end
318
+
319
+ # Retém compatibilidade com a implementação existente.
320
+ # A implementação mais rica (retornando objetos) está em Datajud::Client
321
+
322
+ # Retorna um objeto Datajud::Processo ou nil
323
+ def self.find(numero, tribunal = nil, **kwargs)
324
+ tribunal = kwargs[:tribunal] if tribunal.nil? && kwargs.key?(:tribunal)
325
+ Datajud::Client.find(numero, tribunal: tribunal)
326
+ end
327
+
328
+ # Mantém método antigo para compatibilidade (retorna hash com dados brutos)
329
+ def self.processo(numero, tribunal = nil, **kwargs)
330
+ tribunal = kwargs[:tribunal] if tribunal.nil? && kwargs.key?(:tribunal)
331
+ # A lógica original permanecida aqui para backward-compat
332
+ siglas_consulta = if tribunal
333
+ Array(tribunal).flatten.map { |t| t.to_s.downcase }
334
+ elsif (siglas_cnj = siglas_por_cnj(numero))
335
+ if configuration.fallback_all_on_miss
336
+ siglas_cnj + (TRIBUNAIS_SIGLAS - siglas_cnj)
337
+ else
338
+ siglas_cnj
339
+ end
340
+ elsif configuration.tribunais.any?
341
+ configuration.tribunais.map { |t| t.to_s.downcase }
342
+ else
343
+ TRIBUNAIS_SIGLAS
344
+ end
57
345
  resultado = nil
58
346
 
59
347
  siglas_consulta.each do |sigla|
60
- endpoint = "#{BASE_ENDPT}/api_publica_#{sigla}/_search"
61
- payload = {
62
- "query": {
63
- "bool": {
64
- "must": [
65
- { "match": { "numeroProcesso": numero } }
66
- ]
67
- }
348
+ resposta = ApiClient.buscar_processo(numero, sigla)
349
+ next if resposta.is_a?(Hash) && resposta[:error]
350
+
351
+ hits = resposta.is_a?(Hash) ? resposta.dig('hits', 'hits') : nil
352
+ next if hits.nil? || hits.empty?
353
+
354
+ proc = hits[0]['_source']
355
+
356
+ resultado = {
357
+ tribunal: tribunal_from(sigla, proc),
358
+ processo: {
359
+ numero: proc['numeroProcesso'],
360
+ vara: proc['orgaoJulgador'] ? {
361
+ nome: proc['orgaoJulgador']['nome'],
362
+ codigo: proc['orgaoJulgador']['codigo'],
363
+ comarca: comarca_from(proc['orgaoJulgador'], sigla)
364
+ } : nil,
365
+ situacao: proc['situacao'],
366
+ origem: proc['origem'],
367
+ instancia: proc['grau'],
368
+ classe: proc['classeProcessual'] || proc['classe'],
369
+ assunto: proc['assuntos'],
370
+ partes: partes_from(proc),
371
+ andamentos: (proc['movimentacoes'] || proc['movimentos'])&.map do |mv|
372
+ {
373
+ descricao: mv['descricao'] || mv['nome'] || mv.dig('tipoMovimento', 'nome') || mv.dig('tipo', 'nome'),
374
+ data: mv['dataHora'] || mv['data'],
375
+ tipo: mv['codigoTipoMovimento'] || mv['codigo'] || mv.dig('tipoMovimento', 'codigo') || mv.dig('tipo', 'codigo')
376
+ }
377
+ end,
378
+ documentos: proc['documentos']&.map do |doc|
379
+ {
380
+ titulo: doc['nomeDocumento'],
381
+ tipo: doc['tipoDocumento'],
382
+ data: doc['dataJuntada'],
383
+ assinatura_digital: doc['assinaturaDigital']
384
+ }
385
+ end,
386
+ audiencias: proc['audiencias']&.map do |aud|
387
+ {
388
+ data_hora: aud['dataHora'],
389
+ tipo: aud['tipo'],
390
+ status: aud['statusAudiencia'],
391
+ observacao: aud['observacao']
392
+ }
393
+ end
68
394
  }
69
395
  }
396
+ break
397
+ end
398
+ resultado
399
+ end
70
400
 
71
- uri = URI(endpoint)
72
- req = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json')
73
- req.body = payload.to_json
74
- req['Authorization'] = "APIKey #{api_key}"
401
+ def self.partes_from(proc)
402
+ partes = proc['partes'] || proc['partesProcessuais']
403
+ partes = Array(partes) if partes
75
404
 
76
- http = Net::HTTP.new(uri.hostname, uri.port)
77
- http.use_ssl = true
78
- resp = http.request(req)
405
+ if partes.nil? || partes.empty?
406
+ ativos = Array(proc['poloAtivo'] || proc['parteAtiva'] || proc['partesAtivas'])
407
+ passivos = Array(proc['poloPassivo'] || proc['partePassiva'] || proc['partesPassivas'])
408
+ partes = ativos.map { |p| p.merge('polo' => 'ATIVO') } + passivos.map { |p| p.merge('polo' => 'PASSIVO') }
409
+ end
79
410
 
80
- # Se falhar por chave expirada:
81
- if [401, 403].include?(resp.code.to_i)
82
- reset_api_key
83
- req['Authorization'] = "APIKey #{api_key}"
84
- resp = http.request(req)
85
- end
411
+ return nil if partes.nil? || partes.empty?
86
412
 
87
- next unless resp.code.to_i == 200
88
-
89
- processos = JSON.parse(resp.body)
90
- if processos['hits'] && !processos['hits']['hits'].empty?
91
- proc = processos['hits']['hits'][0]['_source']
92
-
93
- resultado = {
94
- tribunal: sigla.upcase,
95
- processo: {
96
- numero: proc['numeroProcesso'],
97
- vara: proc['orgaoJulgador'] ? {
98
- nome: proc['orgaoJulgador']['nome'],
99
- codigo: proc['orgaoJulgador']['codigo'],
100
- comarca: proc['orgaoJulgador']['comarca'],
101
- tribunal: sigla.upcase
102
- } : nil,
103
- situacao: proc['situacao'],
104
- origem: proc['origem'],
105
- instancia: proc['grau'],
106
- classe: proc['classeProcessual'],
107
- assunto: proc['assuntos'],
108
- partes: proc['partes']&.map do |p|
109
- {
110
- nome: p['nome'],
111
- tipo: p['tipoParte'],
112
- documento: p['documento']
113
- }
114
- end,
115
- andamentos: proc['movimentacoes']&.map do |mv|
116
- {
117
- descricao: mv['descricao'],
118
- data: mv['dataHora'],
119
- tipo: mv['codigoTipoMovimento']
120
- }
121
- end,
122
- documentos: proc['documentos']&.map do |doc|
123
- {
124
- titulo: doc['nomeDocumento'],
125
- tipo: doc['tipoDocumento'],
126
- data: doc['dataJuntada'],
127
- assinatura_digital: doc['assinaturaDigital']
128
- }
129
- end,
130
- audiencias: proc['audiencias']&.map do |aud|
131
- {
132
- data_hora: aud['dataHora'],
133
- tipo: aud['tipo'],
134
- status: aud['statusAudiencia'],
135
- observacao: aud['observacao']
136
- }
137
- end
138
- }
139
- }
140
- break
413
+ partes.map do |p|
414
+ {
415
+ nome: p['nome'] || p['nomeParte'] || p['parteNome'],
416
+ tipo: p['tipoParte'] || p['tipo'] || p['polo'] || p['qualificacao'],
417
+ documento: p['documento'] || p['cpfCnpj'] || p['numeroDocumento']
418
+ }
419
+ end
420
+ end
421
+
422
+ def self.tribunal_from(sigla, proc)
423
+ sigla_up = sigla.to_s.upcase
424
+ nome = TRIBUNAL_NOMES[sigla.to_s.downcase] || proc['tribunal'] || sigla_up
425
+ esfera = esfera_from_sigla(sigla_up)
426
+
427
+ { nome: nome, sigla: sigla_up, esfera: esfera }
428
+ end
429
+
430
+ def self.esfera_from_sigla(sigla)
431
+ key = ESFERA_BY_PREFIX.keys.find { |prefix| sigla.start_with?(prefix) }
432
+ ESFERA_BY_PREFIX[key] || "Desconhecida"
433
+ end
434
+
435
+ def self.endpoints_table(tribunais = SUPERIORES_NOMES.keys)
436
+ rows = tribunais.map do |sigla|
437
+ nome = TRIBUNAL_NOMES[sigla] || sigla.to_s.upcase
438
+ endpoint_sigla = endpoint_alias(sigla)
439
+ url = "#{configuration.base_endpoint}/api_publica_#{endpoint_sigla}/_search"
440
+ "<tr><td>#{nome}</td><td><a href=\"#{url}\" target=\"_blank\" rel=\"noopener noreferrer\">#{url}</a></td></tr>"
441
+ end
442
+
443
+ "<table><tr><th>Tribunal</th><th>Url</th></tr>#{rows.join}</table>"
444
+ end
445
+
446
+ def self.endpoint_alias(sigla)
447
+ sigla = sigla.to_s.downcase
448
+ return sigla.gsub(/^tre/, 'tre-') if sigla.start_with?('tre') && !sigla.include?('-')
449
+
450
+ sigla
451
+ end
452
+
453
+ def self.request_with_retry(http, req)
454
+ attempts = 0
455
+ begin
456
+ attempts += 1
457
+ http.request(req)
458
+ rescue Net::OpenTimeout, Net::ReadTimeout, Errno::ECONNRESET, Errno::ETIMEDOUT
459
+ raise if attempts > configuration.retries
460
+
461
+ sleep(configuration.retry_wait) if configuration.retry_wait && configuration.retry_wait.positive?
462
+ retry
463
+ end
464
+ end
465
+
466
+ def self.comarca_from(orgao_julgador, sigla)
467
+ return nil unless orgao_julgador
468
+
469
+ comarca = orgao_julgador['comarca']
470
+
471
+ if comarca.is_a?(Hash)
472
+ nome = comarca['nome'] || comarca['descricao'] || comarca['nomeComarca']
473
+ uf = comarca['uf'] || comarca['siglaUf'] || comarca['estado']
474
+ return { nome: nome, uf: uf, tribunal: sigla.upcase }
475
+ end
476
+
477
+ nome = comarca || orgao_julgador['nome']
478
+ uf = nil
479
+ if orgao_julgador['codigoMunicipioIBGE']
480
+ uf = uf_from_ibge_code(orgao_julgador['codigoMunicipioIBGE'])
481
+ if uf.nil? && configuration.lookup_ibge
482
+ uf = ibge_uf_from(orgao_julgador['codigoMunicipioIBGE'])
141
483
  end
142
484
  end
143
- resultado
485
+
486
+ return nil unless nome
487
+
488
+ { nome: nome, uf: uf, tribunal: sigla.upcase }
489
+ end
490
+
491
+ def self.ibge_uf_from(codigo_municipio)
492
+ @ibge_uf_cache ||= {}
493
+ codigo = codigo_municipio.to_s.strip
494
+ return @ibge_uf_cache[codigo] if @ibge_uf_cache.key?(codigo)
495
+
496
+ begin
497
+ uri = URI("#{configuration.ibge_base_url}/#{codigo}")
498
+ response = Net::HTTP.get(uri)
499
+ data = JSON.parse(response)
500
+ uf = data.dig('microrregiao', 'mesorregiao', 'UF', 'sigla') || data.dig('regiao-imediata', 'regiao-intermediaria', 'UF', 'sigla')
501
+ @ibge_uf_cache[codigo] = uf
502
+ rescue StandardError
503
+ @ibge_uf_cache[codigo] = nil
504
+ end
505
+
506
+ @ibge_uf_cache[codigo]
507
+ end
508
+
509
+ def self.uf_from_ibge_code(codigo_municipio)
510
+ codigo = codigo_municipio.to_s.strip
511
+ return nil if codigo.length < 2
512
+
513
+ IBGE_UF_SIGLAS[codigo[0, 2]]
144
514
  end
145
515
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: datajud
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - PablUoo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-11-25 00:00:00.000000000 Z
11
+ date: 2026-03-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: nokogiri
@@ -72,8 +72,13 @@ files:
72
72
  - Rakefile
73
73
  - bin/console
74
74
  - bin/setup
75
+ - examples/find.rb
75
76
  - lib/datajud.rb
77
+ - lib/datajud/api_client.rb
78
+ - lib/datajud/client.rb
79
+ - lib/datajud/configuration.rb
76
80
  - lib/datajud/key_fetcher.rb
81
+ - lib/datajud/process.rb
77
82
  - lib/datajud/version.rb
78
83
  - sig/datajud.rbs
79
84
  homepage: https://github.com/PablUoo/datajud