focus_nfe 1.0.0

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.
Files changed (206) hide show
  1. checksums.yaml +7 -0
  2. data/.git-hooks/pre_push/steep.rb +18 -0
  3. data/.git-hooks/pre_push/yard_doc.rb +18 -0
  4. data/.gitattributes +1 -0
  5. data/.overcommit.yml +69 -0
  6. data/.rspec +3 -0
  7. data/.yardopts +11 -0
  8. data/CHANGELOG.md +77 -0
  9. data/CLAUDE.md +118 -0
  10. data/CODE_OF_CONDUCT.md +10 -0
  11. data/LICENSE.txt +21 -0
  12. data/README.md +348 -0
  13. data/Rakefile +105 -0
  14. data/data/schemas/schema_cte.json +2793 -0
  15. data/data/schemas/schema_cte_os.json +1335 -0
  16. data/data/schemas/schema_cte_os_transporte_rodoviario.json +109 -0
  17. data/data/schemas/schema_cte_transporte_aereo.json +115 -0
  18. data/data/schemas/schema_cte_transporte_aquaviario.json +174 -0
  19. data/data/schemas/schema_cte_transporte_dutoviario.json +65 -0
  20. data/data/schemas/schema_cte_transporte_ferroviario.json +144 -0
  21. data/data/schemas/schema_cte_transporte_multimodal.json +45 -0
  22. data/data/schemas/schema_cte_transporte_rodoviario.json +78 -0
  23. data/data/schemas/schema_dce.json +549 -0
  24. data/data/schemas/schema_mdfe.json +1102 -0
  25. data/data/schemas/schema_mdfe_transporte_aereo.json +44 -0
  26. data/data/schemas/schema_mdfe_transporte_aquaviario.json +209 -0
  27. data/data/schemas/schema_mdfe_transporte_ferroviario.json +99 -0
  28. data/data/schemas/schema_mdfe_transporte_rodoviario.json +628 -0
  29. data/data/schemas/schema_nfcom.json +1859 -0
  30. data/data/schemas/schema_nfe.json +4750 -0
  31. data/data/schemas/schema_nfe_forma_pagamento.json +97 -0
  32. data/data/schemas/schema_nfe_item.json +2574 -0
  33. data/data/schemas/schema_nfgas.json +2316 -0
  34. data/data/schemas/schema_nfse_nacional.json +1847 -0
  35. data/data/schemas/schema_nfse_recebida.json +548 -0
  36. data/lib/focus_nfe/client.rb +162 -0
  37. data/lib/focus_nfe/configuration.rb +104 -0
  38. data/lib/focus_nfe/errors.rb +123 -0
  39. data/lib/focus_nfe/esquemas/campo.rb +171 -0
  40. data/lib/focus_nfe/esquemas/catalogo.rb +34 -0
  41. data/lib/focus_nfe/esquemas/decimal.rb +66 -0
  42. data/lib/focus_nfe/esquemas/esquema.rb +72 -0
  43. data/lib/focus_nfe/esquemas/validador.rb +87 -0
  44. data/lib/focus_nfe/http/adapter.rb +25 -0
  45. data/lib/focus_nfe/http/adapters/net_http.rb +99 -0
  46. data/lib/focus_nfe/http/authentication.rb +23 -0
  47. data/lib/focus_nfe/http/connection.rb +118 -0
  48. data/lib/focus_nfe/http/logging.rb +100 -0
  49. data/lib/focus_nfe/http/response.rb +75 -0
  50. data/lib/focus_nfe/modelos/documento.rb +113 -0
  51. data/lib/focus_nfe/modelos/inutilizacao.rb +75 -0
  52. data/lib/focus_nfe/modelos/pagina.rb +54 -0
  53. data/lib/focus_nfe/recursos/backups.rb +17 -0
  54. data/lib/focus_nfe/recursos/base.rb +91 -0
  55. data/lib/focus_nfe/recursos/ceps.rb +16 -0
  56. data/lib/focus_nfe/recursos/cfops.rb +16 -0
  57. data/lib/focus_nfe/recursos/cnaes.rb +16 -0
  58. data/lib/focus_nfe/recursos/cnpjs.rb +13 -0
  59. data/lib/focus_nfe/recursos/concerns/baixavel.rb +41 -0
  60. data/lib/focus_nfe/recursos/concerns/baixavel_eventos.rb +34 -0
  61. data/lib/focus_nfe/recursos/concerns/cancelavel.rb +25 -0
  62. data/lib/focus_nfe/recursos/concerns/conciliavel.rb +66 -0
  63. data/lib/focus_nfe/recursos/concerns/consultavel.rb +26 -0
  64. data/lib/focus_nfe/recursos/concerns/corrigivel.rb +45 -0
  65. data/lib/focus_nfe/recursos/concerns/corrigivel_cte.rb +60 -0
  66. data/lib/focus_nfe/recursos/concerns/emitivel.rb +51 -0
  67. data/lib/focus_nfe/recursos/concerns/enviavel.rb +40 -0
  68. data/lib/focus_nfe/recursos/concerns/eventavel.rb +46 -0
  69. data/lib/focus_nfe/recursos/concerns/inutilizavel.rb +96 -0
  70. data/lib/focus_nfe/recursos/concerns/listavel.rb +22 -0
  71. data/lib/focus_nfe/recursos/concerns/localizavel.rb +22 -0
  72. data/lib/focus_nfe/recursos/concerns/notificavel.rb +23 -0
  73. data/lib/focus_nfe/recursos/concerns/removivel.rb +20 -0
  74. data/lib/focus_nfe/recursos/concerns/visualizavel.rb +28 -0
  75. data/lib/focus_nfe/recursos/cte.rb +35 -0
  76. data/lib/focus_nfe/recursos/cte_os.rb +29 -0
  77. data/lib/focus_nfe/recursos/ctes_recebidas.rb +38 -0
  78. data/lib/focus_nfe/recursos/dce.rb +16 -0
  79. data/lib/focus_nfe/recursos/emails_bloqueados.rb +31 -0
  80. data/lib/focus_nfe/recursos/empresas.rb +35 -0
  81. data/lib/focus_nfe/recursos/mdfe.rb +78 -0
  82. data/lib/focus_nfe/recursos/municipios.rb +60 -0
  83. data/lib/focus_nfe/recursos/ncms.rb +16 -0
  84. data/lib/focus_nfe/recursos/nfce.rb +19 -0
  85. data/lib/focus_nfe/recursos/nfcom.rb +16 -0
  86. data/lib/focus_nfe/recursos/nfe.rb +106 -0
  87. data/lib/focus_nfe/recursos/nfes_recebidas.rb +56 -0
  88. data/lib/focus_nfe/recursos/nfgas.rb +16 -0
  89. data/lib/focus_nfe/recursos/nfse.rb +18 -0
  90. data/lib/focus_nfe/recursos/nfse_nacional.rb +16 -0
  91. data/lib/focus_nfe/recursos/nfses_nacionais_recebidas.rb +21 -0
  92. data/lib/focus_nfe/recursos/webhooks.rb +22 -0
  93. data/lib/focus_nfe/version.rb +6 -0
  94. data/lib/focus_nfe/webhook.rb +68 -0
  95. data/lib/focus_nfe.rb +124 -0
  96. data/sig/focus_nfe/client.rbs +38 -0
  97. data/sig/focus_nfe/configuration.rbs +29 -0
  98. data/sig/focus_nfe/errors.rbs +59 -0
  99. data/sig/focus_nfe/esquemas/campo.rbs +47 -0
  100. data/sig/focus_nfe/esquemas/catalogo.rbs +8 -0
  101. data/sig/focus_nfe/esquemas/decimal.rbs +25 -0
  102. data/sig/focus_nfe/esquemas/esquema.rbs +30 -0
  103. data/sig/focus_nfe/esquemas/validador.rbs +20 -0
  104. data/sig/focus_nfe/http/adapter.rbs +7 -0
  105. data/sig/focus_nfe/http/adapters/net_http.rbs +25 -0
  106. data/sig/focus_nfe/http/authentication.rbs +9 -0
  107. data/sig/focus_nfe/http/connection.rbs +32 -0
  108. data/sig/focus_nfe/http/logging.rbs +30 -0
  109. data/sig/focus_nfe/http/response.rbs +28 -0
  110. data/sig/focus_nfe/modelos/documento.rbs +34 -0
  111. data/sig/focus_nfe/modelos/inutilizacao.rbs +24 -0
  112. data/sig/focus_nfe/modelos/pagina.rbs +21 -0
  113. data/sig/focus_nfe/recursos/backups.rbs +7 -0
  114. data/sig/focus_nfe/recursos/base.rbs +25 -0
  115. data/sig/focus_nfe/recursos/ceps.rbs +10 -0
  116. data/sig/focus_nfe/recursos/cfops.rbs +10 -0
  117. data/sig/focus_nfe/recursos/cnaes.rbs +10 -0
  118. data/sig/focus_nfe/recursos/cnpjs.rbs +7 -0
  119. data/sig/focus_nfe/recursos/concerns/baixavel.rbs +12 -0
  120. data/sig/focus_nfe/recursos/concerns/baixavel_eventos.rbs +14 -0
  121. data/sig/focus_nfe/recursos/concerns/cancelavel.rbs +9 -0
  122. data/sig/focus_nfe/recursos/concerns/conciliavel.rbs +15 -0
  123. data/sig/focus_nfe/recursos/concerns/consultavel.rbs +9 -0
  124. data/sig/focus_nfe/recursos/concerns/corrigivel.rbs +15 -0
  125. data/sig/focus_nfe/recursos/concerns/corrigivel_cte.rbs +17 -0
  126. data/sig/focus_nfe/recursos/concerns/emitivel.rbs +14 -0
  127. data/sig/focus_nfe/recursos/concerns/enviavel.rbs +15 -0
  128. data/sig/focus_nfe/recursos/concerns/eventavel.rbs +12 -0
  129. data/sig/focus_nfe/recursos/concerns/inutilizavel.rbs +20 -0
  130. data/sig/focus_nfe/recursos/concerns/listavel.rbs +9 -0
  131. data/sig/focus_nfe/recursos/concerns/localizavel.rbs +9 -0
  132. data/sig/focus_nfe/recursos/concerns/notificavel.rbs +9 -0
  133. data/sig/focus_nfe/recursos/concerns/removivel.rbs +9 -0
  134. data/sig/focus_nfe/recursos/concerns/visualizavel.rbs +9 -0
  135. data/sig/focus_nfe/recursos/cte.rbs +17 -0
  136. data/sig/focus_nfe/recursos/cte_os.rbs +17 -0
  137. data/sig/focus_nfe/recursos/ctes_recebidas.rbs +14 -0
  138. data/sig/focus_nfe/recursos/dce.rbs +10 -0
  139. data/sig/focus_nfe/recursos/emails_bloqueados.rbs +12 -0
  140. data/sig/focus_nfe/recursos/empresas.rbs +12 -0
  141. data/sig/focus_nfe/recursos/mdfe.rbs +21 -0
  142. data/sig/focus_nfe/recursos/municipios.rbs +19 -0
  143. data/sig/focus_nfe/recursos/ncms.rbs +10 -0
  144. data/sig/focus_nfe/recursos/nfce.rbs +12 -0
  145. data/sig/focus_nfe/recursos/nfcom.rbs +10 -0
  146. data/sig/focus_nfe/recursos/nfe.rbs +23 -0
  147. data/sig/focus_nfe/recursos/nfes_recebidas.rbs +16 -0
  148. data/sig/focus_nfe/recursos/nfgas.rbs +10 -0
  149. data/sig/focus_nfe/recursos/nfse.rbs +11 -0
  150. data/sig/focus_nfe/recursos/nfse_nacional.rbs +10 -0
  151. data/sig/focus_nfe/recursos/nfses_nacionais_recebidas.rbs +11 -0
  152. data/sig/focus_nfe/recursos/webhooks.rbs +11 -0
  153. data/sig/focus_nfe/webhook.rbs +11 -0
  154. data/sig/focus_nfe.rbs +10 -0
  155. data/spec/focus_nfe/client_spec.rb +208 -0
  156. data/spec/focus_nfe/configuration_spec.rb +121 -0
  157. data/spec/focus_nfe/errors_mapping_spec.rb +68 -0
  158. data/spec/focus_nfe/errors_spec.rb +107 -0
  159. data/spec/focus_nfe/esquemas/campo_spec.rb +291 -0
  160. data/spec/focus_nfe/esquemas/decimal_spec.rb +54 -0
  161. data/spec/focus_nfe/esquemas/esquema_spec.rb +73 -0
  162. data/spec/focus_nfe/esquemas/validador_spec.rb +167 -0
  163. data/spec/focus_nfe/esquemas_spec.rb +42 -0
  164. data/spec/focus_nfe/http/adapter_spec.rb +8 -0
  165. data/spec/focus_nfe/http/adapters/net_http_spec.rb +181 -0
  166. data/spec/focus_nfe/http/authentication_spec.rb +24 -0
  167. data/spec/focus_nfe/http/connection_spec.rb +255 -0
  168. data/spec/focus_nfe/http/logging_spec.rb +83 -0
  169. data/spec/focus_nfe/http/response_spec.rb +161 -0
  170. data/spec/focus_nfe/modelos/documento_spec.rb +150 -0
  171. data/spec/focus_nfe/modelos/inutilizacao_spec.rb +91 -0
  172. data/spec/focus_nfe/modelos/pagina_spec.rb +77 -0
  173. data/spec/focus_nfe/recursos/backups_spec.rb +29 -0
  174. data/spec/focus_nfe/recursos/base_spec.rb +56 -0
  175. data/spec/focus_nfe/recursos/ceps_spec.rb +16 -0
  176. data/spec/focus_nfe/recursos/cfops_spec.rb +16 -0
  177. data/spec/focus_nfe/recursos/cnaes_spec.rb +20 -0
  178. data/spec/focus_nfe/recursos/cnpjs_spec.rb +11 -0
  179. data/spec/focus_nfe/recursos/concerns/emitivel_validacao_spec.rb +158 -0
  180. data/spec/focus_nfe/recursos/cte_os_spec.rb +9 -0
  181. data/spec/focus_nfe/recursos/cte_spec.rb +9 -0
  182. data/spec/focus_nfe/recursos/ctes_recebidas_spec.rb +56 -0
  183. data/spec/focus_nfe/recursos/dce_spec.rb +8 -0
  184. data/spec/focus_nfe/recursos/emails_bloqueados_spec.rb +29 -0
  185. data/spec/focus_nfe/recursos/empresas_spec.rb +45 -0
  186. data/spec/focus_nfe/recursos/mdfe_spec.rb +100 -0
  187. data/spec/focus_nfe/recursos/municipios_spec.rb +58 -0
  188. data/spec/focus_nfe/recursos/ncms_spec.rb +16 -0
  189. data/spec/focus_nfe/recursos/nfce_spec.rb +10 -0
  190. data/spec/focus_nfe/recursos/nfcom_spec.rb +8 -0
  191. data/spec/focus_nfe/recursos/nfe_spec.rb +262 -0
  192. data/spec/focus_nfe/recursos/nfes_recebidas_spec.rb +87 -0
  193. data/spec/focus_nfe/recursos/nfgas_spec.rb +8 -0
  194. data/spec/focus_nfe/recursos/nfse_nacional_spec.rb +8 -0
  195. data/spec/focus_nfe/recursos/nfse_spec.rb +9 -0
  196. data/spec/focus_nfe/recursos/nfses_nacionais_recebidas_spec.rb +17 -0
  197. data/spec/focus_nfe/recursos/webhooks_spec.rb +22 -0
  198. data/spec/focus_nfe/webhook_spec.rb +66 -0
  199. data/spec/focus_nfe_global_configuration_spec.rb +70 -0
  200. data/spec/focus_nfe_require_spec.rb +87 -0
  201. data/spec/focus_nfe_spec.rb +11 -0
  202. data/spec/spec_helper.rb +58 -0
  203. data/spec/support/shared_examples/recurso_fiscal.rb +445 -0
  204. data/spec/support/shared_examples/recurso_leitura.rb +217 -0
  205. data/tools/pull_fields.rb +62 -0
  206. metadata +420 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 52bbed5033ec09928bd4361f6b81913e0592bee928238021ccf74c555482b0fd
4
+ data.tar.gz: b26c1868a8e89f942556332397bbb581fa60915bfdd535ceb4a71efa8eabb89d
5
+ SHA512:
6
+ metadata.gz: bdae6d394dd3525988db27e7ca9eeaec95227ee5002f37f151821ef1c602d944904f45a2f51ab23ef3488ca6d566e86ba3708c1b847a370f9b67b7060f73d32c
7
+ data.tar.gz: cec18edbbe79d1dcb201831e1f7e07ddc1619bf33d1ce1a2e47af0d14140f04665a669937b1d8e4dd0347c36a320afe99635d92418e0314ebac5e351356f346b
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overcommit
4
+ module Hook
5
+ module PrePush
6
+ # Roda `steep check` para garantir que as assinaturas RBS em `sig/`
7
+ # continuam consistentes com a implementação em `lib/`.
8
+ class Steep < Base
9
+ def run
10
+ result = execute(%w[bundle exec steep check])
11
+ return :pass if result.success?
12
+
13
+ [:fail, result.stdout + result.stderr]
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Overcommit
4
+ module Hook
5
+ module PrePush
6
+ # Garante que a documentação YARD é gerada sem warnings
7
+ # (`--fail-on-warning`), espelhando o job `docs` do CI.
8
+ class YardDoc < Base
9
+ def run
10
+ result = execute(%w[bundle exec yard doc --no-output --fail-on-warning])
11
+ return :pass if result.success?
12
+
13
+ [:fail, result.stdout + result.stderr]
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
data/.gitattributes ADDED
@@ -0,0 +1 @@
1
+ data/schemas/*.json linguist-generated=true
data/.overcommit.yml ADDED
@@ -0,0 +1,69 @@
1
+ gemfile: false
2
+
3
+ CommitMsg:
4
+ ALL:
5
+ requires_files: false
6
+
7
+ MessageFormat:
8
+ enabled: true
9
+ pattern: '\A(?:Merge|Revert|fixup!|squash!).*|\A(build|chore|ci|docs|feat|fix|perf|refactor|revert|style|test)(\([\w\-./ ]+\))?!?: .+'
10
+ expected_pattern_message: >-
11
+ A mensagem de commit deve seguir o padrão Conventional Commits:
12
+ <tipo>(escopo opcional): <descrição>. Tipos válidos: build, chore, ci,
13
+ docs, feat, fix, perf, refactor, revert, style, test.
14
+ sample_message: "feat(nfe): adiciona emissão de NFe"
15
+
16
+ CapitalizedSubject:
17
+ enabled: false
18
+
19
+ TextWidth:
20
+ enabled: true
21
+ min_subject_width: 8
22
+ max_subject_width: 72
23
+
24
+ TrailingPeriod:
25
+ enabled: true
26
+
27
+ SingleLineSubject:
28
+ enabled: true
29
+
30
+ EmptyMessage:
31
+ enabled: true
32
+
33
+ PreCommit:
34
+ RuboCop:
35
+ enabled: true
36
+ command: ["bundle", "exec", "rubocop"]
37
+ on_warn: fail
38
+
39
+ TrailingWhitespace:
40
+ enabled: true
41
+ exclude:
42
+ - "data/schemas/**/*"
43
+
44
+ HardTabs:
45
+ enabled: true
46
+
47
+ MergeConflicts:
48
+ enabled: true
49
+
50
+ YamlSyntax:
51
+ enabled: true
52
+
53
+ YardCoverage:
54
+ enabled: true
55
+ min_coverage_percentage: 93
56
+ flags: []
57
+
58
+ PrePush:
59
+ RSpec:
60
+ enabled: true
61
+ command: ["bundle", "exec", "rspec"]
62
+
63
+ Steep:
64
+ enabled: true
65
+ required_executable: "bundle"
66
+
67
+ YardDoc:
68
+ enabled: true
69
+ required_executable: "bundle"
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --require spec_helper
2
+ --format progress
3
+ --color
data/.yardopts ADDED
@@ -0,0 +1,11 @@
1
+ --readme README.md
2
+ --markup markdown
3
+ --charset utf-8
4
+ --output-dir docs
5
+ --protected
6
+ --no-private
7
+ --title "Focus NFe - Cliente Ruby"
8
+ lib/**/*.rb
9
+ -
10
+ CHANGELOG.md
11
+ LICENSE.txt
data/CHANGELOG.md ADDED
@@ -0,0 +1,77 @@
1
+ # Changelog
2
+
3
+ Formato baseado em [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0/)
4
+ e versionamento em [SemVer](https://semver.org/lang/pt-BR/).
5
+
6
+ ## [Unreleased]
7
+
8
+ ## [1.0.0] - 2026-07-03
9
+
10
+ Primeira versão pública. Cliente Ruby não-oficial para a API da
11
+ [Focus NFe](https://focusnfe.com.br), sem dependências de runtime (apenas a
12
+ stdlib).
13
+
14
+ ### Cliente e configuração
15
+
16
+ - `FocusNfe::Client` com dois modos que coexistem: configuração global
17
+ (`FocusNfe.configure`) para aplicações de uma empresa só, e instâncias
18
+ independentes para cenários multi-empresa.
19
+ - Dois tokens da Focus NFe separados: `Configuration#token_empresa`
20
+ (emissão/consulta de documentos e gestão por empresa) e
21
+ `Configuration#token_conta` (consultas auxiliares e gestão de empresas). O
22
+ cliente mantém uma conexão por token e roteia cada recurso para a correta;
23
+ acessar um recurso sem o token exigido levanta `ConfigurationError` antes de
24
+ qualquer ida à rede.
25
+ - Ambientes `:homologacao` e `:producao`, resolvidos para a URL base correta.
26
+ - `timeout`, `logger` e adaptador HTTP configuráveis; adaptador padrão sobre
27
+ `net/http`, sem gems externas.
28
+ - Erros tipados por status HTTP (`FocusNfe::Errors::*`) a partir de
29
+ `FocusNfe::Error`, com o corpo da resposta preservado.
30
+
31
+ ### Documentos emitidos
32
+
33
+ - Recursos `nfe`, `nfce`, `nfse`, `nfse_nacional`, `cte`, `cte_os`, `mdfe`,
34
+ `nfcom`, `dce` e `nfgas`.
35
+ - Operações fiscais conforme cada documento: `emitir`, `consultar`, `cancelar`,
36
+ `inutilizar`, carta de correção e demais eventos, além de download dos XMLs
37
+ e do DANFE/DACTE quando disponível.
38
+ - Eventos próprios do MDF-e: `Mdfe#encerrar`, `Mdfe#incluir_condutor` e
39
+ `Mdfe#incluir_dfe`, devolvendo `Modelos::Documento`.
40
+ - Respostas devolvidas como `Modelos::Documento` (e `Modelos::Inutilizacao`
41
+ para inutilizações).
42
+
43
+ ### Documentos recebidos
44
+
45
+ - Recursos `nfes_recebidas`, `ctes_recebidas` e `nfses_nacionais_recebidas`.
46
+ - Listagem com sincronização incremental paginada (`Modelos::Pagina`),
47
+ consulta, manifestação do destinatário, eventos e download dos XMLs
48
+ (documento e eventos).
49
+
50
+ ### APIs auxiliares (token da conta)
51
+
52
+ - Consultas somente leitura `ceps`, `municipios`, `cfops`, `cnaes`, `ncms` e
53
+ `cnpjs`.
54
+
55
+ ### APIs de gestão
56
+
57
+ - `empresas` (token da conta) para cadastro e manutenção de empresas.
58
+ - `webhooks`, `emails_bloqueados` e `backups` (token da empresa).
59
+
60
+ ### Webhooks inbound
61
+
62
+ - `FocusNfe::Webhook.parse(raw_body)` devolve um `Modelos::Documento`.
63
+ - `FocusNfe::Webhook.autenticado?(headers:, authorization:, authorization_header:)`
64
+ valida a chamada comparando o header recebido com o `authorization` do
65
+ gatilho em tempo constante. Inclui `Modelos::Documento.from_payload` e o erro
66
+ `Errors::WebhookError`.
67
+
68
+ ### Validação client-side (opt-in)
69
+
70
+ - Esquemas de campos (`FocusNfe::Esquemas::*`) derivados de
71
+ `campos.focusnfe.com.br` e empacotados em `data/schemas/`, com validação
72
+ opcional na emissão (`emitir(..., validar: true)`).
73
+
74
+ ### Qualidade
75
+
76
+ - Assinaturas de tipo RBS (`sig/`) verificadas por Steep e documentação YARD em
77
+ português nas APIs públicas.
data/CLAUDE.md ADDED
@@ -0,0 +1,118 @@
1
+ # CLAUDE.md
2
+
3
+ Guidance for Claude Code when working in this repository.
4
+
5
+ ## What this is
6
+
7
+ Unofficial Ruby gem: a client for the [Focus NFe](https://focusnfe.com.br) API (Brazilian electronic
8
+ fiscal documents — NFe, NFCe, NFSe, CTe, MDFe, NFCom, DCe, …). Early stage: most of the gem is still
9
+ to be built; the substantive existing code is the field-scraping tooling (*Field schemas* below).
10
+
11
+ ## Coding conventions
12
+
13
+ ### Identifier language (hybrid: English plumbing, Portuguese domain)
14
+
15
+ Dividing question: **does the identifier name something in the Focus NFe / SEFAZ fiscal domain?**
16
+ Yes → **Portuguese**. The gem's own machinery → **English**.
17
+
18
+ - **English (gem plumbing, not in the API):** classes/modules (`Client`, `Configuration`, `Connection`,
19
+ `Response`, `Adapter`, `Authentication`, `Error`, `Errors::*`); structural methods (`configure`,
20
+ `connection`, `call`, `get`/`post`/`put`/`delete`, `validate!`, `success?`, `from_response`,
21
+ `class_for`); infra config & HTTP terms (`environment`, `timeout`, `logger`, `http_adapter`, `headers`,
22
+ `path`, `params`, `body`, `status`, `url`); all internal vars, private methods, constants.
23
+ - **Portuguese (the API's own vocabulary):** resource accessors / fiscal operations mapping 1:1 to API
24
+ actions (`nfe`, `nfce`, `nfse`, `cte`, `mdfe`, `emitir`, `consultar`, `cancelar`, `inutilizar`,
25
+ `justificativa`, `referencia`); **payload field names verbatim from the schemas — never translated**
26
+ (`natureza_operacao`, `cnpj_emitente`, `valor_total`, …).
27
+ - **Domain values stay Portuguese even behind an English key:** `config.environment = :homologacao`
28
+ (`:producao`/`:homologacao`); fiscal statuses like `"autorizado"`/`"cancelado"`.
29
+ - Debated boundaries: `environment` is English (resolves the base URL; `ambiente` is not an API field);
30
+ `referencia` is Portuguese (the API's `ref`).
31
+
32
+ General Ruby/gem best practices: `frozen_string_literal`, double-quoted strings, Ruby 3.3 target (`.rubocop.yml`).
33
+
34
+ ### Comments
35
+
36
+ - **No unnecessary comments** — names carry intent; no narration, restatement, or banner/section comments.
37
+ - **Only YARD docs allowed**, on public classes/modules/methods, with type tags (`@param`, `@return`,
38
+ `@raise`). **Prose in Portuguese**; type references use the real English identifier (`@return [FocusNfe::Configuration]`).
39
+ - A genuinely non-obvious *why* (workaround, external constraint) goes in the method's YARD doc, not inline.
40
+
41
+ ## TDD (mandatory — hard rule)
42
+
43
+ Red → Green → Refactor for every behavior. **No production code without a failing spec first** (new
44
+ classes, methods, branches arrive test-first; each bug fix starts with a reproducing spec).
45
+
46
+ - **RSpec** under `spec/`, mirroring `lib/` (`spec/focus_nfe/recursos/nfe_spec.rb`, …).
47
+ - HTTP never hit for real — stub with **WebMock** (VCR for recorded interactions if useful). Cover both
48
+ `:homologacao` and `:producao` base URLs.
49
+ - `bundle exec rake` (RSpec + RuboCop) must stay green before any commit.
50
+
51
+ ## Commands
52
+
53
+ - `bin/setup` — install deps; then `bundle exec overcommit --install` (git hooks, see below).
54
+ - `bin/console` — IRB with the gem loaded.
55
+ - `bin/rspec` / `bin/rubocop` — binstubs (faster than `bundle exec`). `bin/rubocop -a` auto-corrects.
56
+ - `bundle exec rake` — default; runs **RSpec + RuboCop**. Keep green before committing.
57
+ - `bundle exec rake ci` — roda **localmente todas as verificações do CI** (`.github/workflows/ci.yml`):
58
+ specs, RuboCop, Steep, YARD (`--fail-on-warning`), cobertura de docs e schemas atualizados. Continua
59
+ mesmo se um passo falhar e imprime um resumo no fim — pegue o CI quebrado antes de enviar ao GitHub.
60
+ - `bundle exec rake steep` — **Steep** type-check (`sig/` vs `lib/`). Standalone, *not* in default rake;
61
+ CI gates it in a `typecheck` job. See *Type signatures*.
62
+ - `bundle exec rake pull_fields` — regenerate field schemas into `data/schemas/`.
63
+ - `bundle exec rake coverage:open` — open SimpleCov HTML report (generate first via `bin/rspec`/`rake spec`;
64
+ configured atop `spec/spec_helper.rb`, line+branch; `coverage/` git-ignored).
65
+ - `bundle exec rake install` / `release` — build/publish (gemspec metadata still has TODOs).
66
+
67
+ CI (`.github/workflows/ci.yml`) pins Ruby `4.0.2`; gemspec requires `>= 3.3.0`.
68
+
69
+ ## Git hooks / commits (overcommit + Conventional Commits)
70
+
71
+ Managed by [overcommit](https://github.com/sds/overcommit) (`.overcommit.yml`); activate once with
72
+ `bundle exec overcommit --install`. After editing `.overcommit.yml`, re-sign: `bundle exec overcommit --sign`.
73
+
74
+ - **pre-commit** — `rubocop` on changed files + whitespace/tab/merge-conflict/YAML checks.
75
+ - **pre-push** — full `rspec` suite.
76
+ - **commit-msg** — [Conventional Commits](https://www.conventionalcommits.org): `<tipo>(escopo)!: <descrição>`.
77
+ Types: `build`, `chore`, `ci`, `docs`, `feat`, `fix`, `perf`, `refactor`, `revert`, `style`, `test`.
78
+ Subject ≤ 72 cols, no trailing period (`Merge`/`Revert`/`fixup!`/`squash!` exempt).
79
+
80
+ ## Field schemas (source of truth for API fields)
81
+
82
+ The request/field layer is derived from `campos.focusnfe.com.br`, not hand-transcribed.
83
+
84
+ - `tools/pull_fields.rb` fetches each page, extracts the embedded `__NEXT_DATA__` JSON
85
+ (`props.pageProps.json.object_attributes`), and writes `data/schemas/schema_<name>.json` per document
86
+ type (URL map at the top of the script).
87
+ - Each entry: `{ name, description, type, required, tag }`, optionally `enum`, `reforma_tributaria`, and a
88
+ nested `collection` (with `collection_type`). `name` = JSON field the API expects; `tag` = XML tag;
89
+ `type` encodes Brazilian fiscal type/length (`String[1-60]`, `Integer[1-9]`, `Decimal[13.2]`, `Coleção[0-500]`).
90
+ - `data/schemas/` is git-tracked and packaged (gemspec `git ls-files`); powers opt-in client-side validation
91
+ (`FocusNfe::Esquemas::*`, `emitir(..., validar: true)`).
92
+
93
+ **Never edit `data/schemas/*.json` by hand** — generated by `rake pull_fields`. To change a schema, edit the
94
+ source / `tools/pull_fields.rb`, rerun, and commit the regenerated output. CI's `schemas` job regenerates on
95
+ every PR and fails on any diff.
96
+
97
+ ## Type signatures (RBS + Steep)
98
+
99
+ Hand-written RBS under `sig/`, checked by Steep — `steep check` must stay green (CI `typecheck` job, Ruby 3.4;
100
+ local `bundle exec rake steep`, standalone to keep the 3.3–4.0 matrix fast). `Steepfile` has one `target :lib`
101
+ checking `lib` against `sig` with stdlib `json`, `uri`, `net-http`, `timeout` (no `rbs_collection` — zero
102
+ runtime deps). `sig/` is packaged with the gem; `Steepfile`/`rbs_collection.*` are excluded via the gemspec
103
+ reject-list.
104
+
105
+ - **`sig/` mirrors `lib/`, one file per `.rb`.** Keep in sync — a new class/method/branch arrives with its
106
+ signature. **Hand-written, never generated** (`rbs prototype` loses overloads, self-types, `define_method`'d methods).
107
+ - **Typing boundary mirrors the naming rule:** gem plumbing is **precise** (`Response#status: Integer`,
108
+ `raw_body: String?`, `Configuration`/`Connection`/`Adapter` shapes, `Campo`'s parsed type/size); the
109
+ **fiscal payload/JSON domain is `untyped`** (`Response#body`, `Documento` fields & `#dados`, every
110
+ `**dados`/`**opcoes`/`**filtros`, raw-body returns of auxiliary/recebidas/management resources). When unsure
111
+ at a payload boundary, widen to `Hash[untyped, untyped]`/`untyped`.
112
+ - **Mixins use RBS self-types:** each `Recursos::Concerns::*` is `module X : FocusNfe::Recursos::Base` so Steep
113
+ resolves the host's private `connection`/`caminho_*`/`esquemas_extras`.
114
+ - **No `# steep:ignore`** (the comment rule allows only YARD). When Steep can't follow the code (e.g.
115
+ `define_method` doesn't rebind `self`), **restructure to explicit methods** instead of silencing — why
116
+ `HTTP::Connection`'s verbs and `Modelos::Documento`'s readers are written out. For stdlib nil-narrowing,
117
+ capture into a local and guard.
118
+ - `Ruby::UnannotatedEmptyCollection` (empty `{}`) is disabled in `Steepfile`.
@@ -0,0 +1,10 @@
1
+ # Code of Conduct
2
+
3
+ "focus_nfe" follows [The Ruby Community Conduct Guideline](https://www.ruby-lang.org/en/conduct) in all "collaborative space", which is defined as community communications channels (such as mailing lists, submitted patches, commit comments, etc.):
4
+
5
+ * Participants will be tolerant of opposing views.
6
+ * Participants must ensure that their language and actions are free of personal attacks and disparaging personal remarks.
7
+ * When interpreting the words and actions of others, participants should always assume good intentions.
8
+ * Behaviour which can be reasonably considered harassment will not be tolerated.
9
+
10
+ If you have any concerns about behaviour within this project, please contact us at ["wilfisonbatista@gmail.com"](mailto:"wilfisonbatista@gmail.com").
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2026 wilfison
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.