datajud 0.1.1 → 0.1.2

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: 10c59cd9f52f93532e97686b95b2ce3a5f482c6cd42c7b110a860c21e60c268b
4
+ data.tar.gz: 7886282868f709f225b981e62932985630387d120020d0b0ebe962c6251fc695
5
5
  SHA512:
6
- metadata.gz: c460a3f2464dd88e681bd86255948af4adb184b7006901f96e24ffabb3bd3083d07ee86492f3d259a2cc62d89687960bd318d271a97a2ba5c86aa423db729884
7
- data.tar.gz: 8835e83491188e7d35864ae9c132f418fe4f1cd2d80528d9d587b1527d92bd5bdc348924ab3d59c626246e8b4bb6b5f5f5bbc41dd4d651ee7adc955f6025a879
6
+ metadata.gz: 80e24e11e26c39faff385fa928f7f8b6125ed307bd40b5826527c75a09e30f51e7265213bcbe7c1ef30c2c15e86a2d0367f580d132f7e4587bd703ef1f4fc0fa
7
+ data.tar.gz: 29fb5433cf555e0df1df5f1a3f79f52a50c53a946ea5de7ce2c0a36107c99613fb304d0a0bf99a665bc587857d4cc4e7dc1c5c03389e39d59c6f551a08b181e6
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.2)
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,54 @@
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
+
15
+ http = Net::HTTP.new(url.host, url.port)
16
+ http.use_ssl = (url.scheme == "https")
17
+ http.open_timeout = Datajud.configuration.open_timeout
18
+ http.read_timeout = Datajud.configuration.read_timeout
19
+
20
+ request = Net::HTTP::Post.new(url)
21
+ request['Authorization'] = "APIKey #{Datajud.api_key}"
22
+ request['Content-Type'] = 'application/json'
23
+ request.body = { query: filtros }.to_json
24
+
25
+ begin
26
+ response = Datajud.request_with_retry(http, request)
27
+ if response.is_a?(Net::HTTPSuccess)
28
+ JSON.parse(response.body)
29
+ else
30
+ { error: response.message, status: response.code, body: response.body }
31
+ end
32
+ rescue SocketError => e
33
+ { error: "Falha de conexão: #{e.message}" }
34
+ rescue Errno::ECONNRESET => e
35
+ { error: "Conexão resetada pelo servidor: #{e.message}" }
36
+ rescue EOFError => e
37
+ { error: "Resposta inesperada da API: #{e.message}" }
38
+ rescue StandardError => e
39
+ { error: "Erro desconhecido: #{e.message}" }
40
+ end
41
+ end
42
+
43
+ # Busca por número de processo (atalho)
44
+ def self.buscar_processo(numero_processo, tribunal)
45
+ filtros = { match: { numeroProcesso: numero_processo } }
46
+ buscar(tribunal, filtros)
47
+ end
48
+ end
49
+ end
50
+
51
+ # Alias para compatibilidade com código legado
52
+ module DataJud
53
+ ApiClient = Datajud::ApiClient
54
+ end
@@ -0,0 +1,13 @@
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)
7
+ raw = Datajud.processo(numero, tribunal: tribunal)
8
+ return nil unless raw && raw[:processo] || raw && raw['processo']
9
+
10
+ Datajud::Processo.new(raw)
11
+ end
12
+ end
13
+ 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,51 @@
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 partes
26
+ partes = @data['partes'] || @data[:partes] || []
27
+ partes.map do |p|
28
+ OpenStruct.new(
29
+ nome: p['nome'] || p[:nome],
30
+ tipo: p['tipo'] || p['tipoParte'] || p[:tipo],
31
+ documento: p['documento'] || p[:documento]
32
+ )
33
+ end
34
+ end
35
+
36
+ def movimentacoes
37
+ mov = @data['andamentos'] || @data[:andamentos] || @data['movimentacoes'] || @data[:movimentacoes]
38
+ (mov || []).map do |m|
39
+ OpenStruct.new(
40
+ descricao: m['descricao'] || m[:descricao],
41
+ data: m['data'] || m['dataHora'] || m[:data],
42
+ tipo: m['tipo'] || m['codigoTipoMovimento'] || m[:tipo]
43
+ )
44
+ end
45
+ end
46
+
47
+ def to_h
48
+ { tribunal: tribunal, processo: data }
49
+ end
50
+ end
51
+ 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.2"
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,225 @@ module Datajud
52
289
  @api_key = nil
53
290
  end
54
291
 
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)
324
+ Datajud::Client.find(numero, tribunal: tribunal)
325
+ end
326
+
327
+ # Mantém método antigo para compatibilidade (retorna hash com dados brutos)
55
328
  def self.processo(numero, tribunal: nil)
56
- siglas_consulta = tribunal ? Array(tribunal).flatten.map { |t| t.to_s.downcase } : TRIBUNAIS_SIGLAS
329
+ # A lógica original permanecida aqui para backward-compat
330
+ siglas_consulta = if tribunal
331
+ Array(tribunal).flatten.map { |t| t.to_s.downcase }
332
+ elsif (siglas_cnj = siglas_por_cnj(numero))
333
+ if configuration.fallback_all_on_miss
334
+ siglas_cnj + (TRIBUNAIS_SIGLAS - siglas_cnj)
335
+ else
336
+ siglas_cnj
337
+ end
338
+ elsif configuration.tribunais.any?
339
+ configuration.tribunais.map { |t| t.to_s.downcase }
340
+ else
341
+ TRIBUNAIS_SIGLAS
342
+ end
57
343
  resultado = nil
58
344
 
59
345
  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
- }
346
+ resposta = ApiClient.buscar_processo(numero, sigla)
347
+ next if resposta.is_a?(Hash) && resposta[:error]
348
+
349
+ hits = resposta.is_a?(Hash) ? resposta.dig('hits', 'hits') : nil
350
+ next if hits.nil? || hits.empty?
351
+
352
+ proc = hits[0]['_source']
353
+
354
+ resultado = {
355
+ tribunal: tribunal_from(sigla, proc),
356
+ processo: {
357
+ numero: proc['numeroProcesso'],
358
+ vara: proc['orgaoJulgador'] ? {
359
+ nome: proc['orgaoJulgador']['nome'],
360
+ codigo: proc['orgaoJulgador']['codigo'],
361
+ comarca: comarca_from(proc['orgaoJulgador'], sigla)
362
+ } : nil,
363
+ situacao: proc['situacao'],
364
+ origem: proc['origem'],
365
+ instancia: proc['grau'],
366
+ classe: proc['classeProcessual'] || proc['classe'],
367
+ assunto: proc['assuntos'],
368
+ partes: partes_from(proc),
369
+ andamentos: (proc['movimentacoes'] || proc['movimentos'])&.map do |mv|
370
+ {
371
+ descricao: mv['descricao'] || mv['nome'] || mv.dig('tipoMovimento', 'nome') || mv.dig('tipo', 'nome'),
372
+ data: mv['dataHora'] || mv['data'],
373
+ tipo: mv['codigoTipoMovimento'] || mv['codigo'] || mv.dig('tipoMovimento', 'codigo') || mv.dig('tipo', 'codigo')
374
+ }
375
+ end,
376
+ documentos: proc['documentos']&.map do |doc|
377
+ {
378
+ titulo: doc['nomeDocumento'],
379
+ tipo: doc['tipoDocumento'],
380
+ data: doc['dataJuntada'],
381
+ assinatura_digital: doc['assinaturaDigital']
382
+ }
383
+ end,
384
+ audiencias: proc['audiencias']&.map do |aud|
385
+ {
386
+ data_hora: aud['dataHora'],
387
+ tipo: aud['tipo'],
388
+ status: aud['statusAudiencia'],
389
+ observacao: aud['observacao']
390
+ }
391
+ end
68
392
  }
69
393
  }
394
+ break
395
+ end
396
+ resultado
397
+ end
70
398
 
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}"
399
+ def self.partes_from(proc)
400
+ partes = proc['partes'] || proc['partesProcessuais']
401
+ partes = Array(partes) if partes
75
402
 
76
- http = Net::HTTP.new(uri.hostname, uri.port)
77
- http.use_ssl = true
78
- resp = http.request(req)
403
+ if partes.nil? || partes.empty?
404
+ ativos = Array(proc['poloAtivo'] || proc['parteAtiva'] || proc['partesAtivas'])
405
+ passivos = Array(proc['poloPassivo'] || proc['partePassiva'] || proc['partesPassivas'])
406
+ partes = ativos.map { |p| p.merge('polo' => 'ATIVO') } + passivos.map { |p| p.merge('polo' => 'PASSIVO') }
407
+ end
79
408
 
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
409
+ return nil if partes.nil? || partes.empty?
86
410
 
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
411
+ partes.map do |p|
412
+ {
413
+ nome: p['nome'] || p['nomeParte'] || p['parteNome'],
414
+ tipo: p['tipoParte'] || p['tipo'] || p['polo'] || p['qualificacao'],
415
+ documento: p['documento'] || p['cpfCnpj'] || p['numeroDocumento']
416
+ }
417
+ end
418
+ end
419
+
420
+ def self.tribunal_from(sigla, proc)
421
+ sigla_up = sigla.to_s.upcase
422
+ nome = TRIBUNAL_NOMES[sigla.to_s.downcase] || proc['tribunal'] || sigla_up
423
+ esfera = esfera_from_sigla(sigla_up)
424
+
425
+ { nome: nome, sigla: sigla_up, esfera: esfera }
426
+ end
427
+
428
+ def self.esfera_from_sigla(sigla)
429
+ key = ESFERA_BY_PREFIX.keys.find { |prefix| sigla.start_with?(prefix) }
430
+ ESFERA_BY_PREFIX[key] || "Desconhecida"
431
+ end
432
+
433
+ def self.endpoints_table(tribunais = SUPERIORES_NOMES.keys)
434
+ rows = tribunais.map do |sigla|
435
+ nome = TRIBUNAL_NOMES[sigla] || sigla.to_s.upcase
436
+ endpoint_sigla = endpoint_alias(sigla)
437
+ url = "#{configuration.base_endpoint}/api_publica_#{endpoint_sigla}/_search"
438
+ "<tr><td>#{nome}</td><td><a href=\"#{url}\" target=\"_blank\" rel=\"noopener noreferrer\">#{url}</a></td></tr>"
439
+ end
440
+
441
+ "<table><tr><th>Tribunal</th><th>Url</th></tr>#{rows.join}</table>"
442
+ end
443
+
444
+ def self.endpoint_alias(sigla)
445
+ sigla = sigla.to_s.downcase
446
+ return sigla.gsub(/^tre/, 'tre-') if sigla.start_with?('tre') && !sigla.include?('-')
447
+
448
+ sigla
449
+ end
450
+
451
+ def self.request_with_retry(http, req)
452
+ attempts = 0
453
+ begin
454
+ attempts += 1
455
+ http.request(req)
456
+ rescue Net::OpenTimeout, Net::ReadTimeout, Errno::ECONNRESET, Errno::ETIMEDOUT
457
+ raise if attempts > configuration.retries
458
+
459
+ sleep(configuration.retry_wait) if configuration.retry_wait && configuration.retry_wait.positive?
460
+ retry
461
+ end
462
+ end
463
+
464
+ def self.comarca_from(orgao_julgador, sigla)
465
+ return nil unless orgao_julgador
466
+
467
+ comarca = orgao_julgador['comarca']
468
+
469
+ if comarca.is_a?(Hash)
470
+ nome = comarca['nome'] || comarca['descricao'] || comarca['nomeComarca']
471
+ uf = comarca['uf'] || comarca['siglaUf'] || comarca['estado']
472
+ return { nome: nome, uf: uf, tribunal: sigla.upcase }
473
+ end
474
+
475
+ nome = comarca || orgao_julgador['nome']
476
+ uf = nil
477
+ if orgao_julgador['codigoMunicipioIBGE']
478
+ uf = uf_from_ibge_code(orgao_julgador['codigoMunicipioIBGE'])
479
+ if uf.nil? && configuration.lookup_ibge
480
+ uf = ibge_uf_from(orgao_julgador['codigoMunicipioIBGE'])
141
481
  end
142
482
  end
143
- resultado
483
+
484
+ return nil unless nome
485
+
486
+ { nome: nome, uf: uf, tribunal: sigla.upcase }
487
+ end
488
+
489
+ def self.ibge_uf_from(codigo_municipio)
490
+ @ibge_uf_cache ||= {}
491
+ codigo = codigo_municipio.to_s.strip
492
+ return @ibge_uf_cache[codigo] if @ibge_uf_cache.key?(codigo)
493
+
494
+ begin
495
+ uri = URI("#{configuration.ibge_base_url}/#{codigo}")
496
+ response = Net::HTTP.get(uri)
497
+ data = JSON.parse(response)
498
+ uf = data.dig('microrregiao', 'mesorregiao', 'UF', 'sigla') || data.dig('regiao-imediata', 'regiao-intermediaria', 'UF', 'sigla')
499
+ @ibge_uf_cache[codigo] = uf
500
+ rescue StandardError
501
+ @ibge_uf_cache[codigo] = nil
502
+ end
503
+
504
+ @ibge_uf_cache[codigo]
505
+ end
506
+
507
+ def self.uf_from_ibge_code(codigo_municipio)
508
+ codigo = codigo_municipio.to_s.strip
509
+ return nil if codigo.length < 2
510
+
511
+ IBGE_UF_SIGLAS[codigo[0, 2]]
144
512
  end
145
513
  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.2
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-11 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