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.
- checksums.yaml +7 -0
- data/.git-hooks/pre_push/steep.rb +18 -0
- data/.git-hooks/pre_push/yard_doc.rb +18 -0
- data/.gitattributes +1 -0
- data/.overcommit.yml +69 -0
- data/.rspec +3 -0
- data/.yardopts +11 -0
- data/CHANGELOG.md +77 -0
- data/CLAUDE.md +118 -0
- data/CODE_OF_CONDUCT.md +10 -0
- data/LICENSE.txt +21 -0
- data/README.md +348 -0
- data/Rakefile +105 -0
- data/data/schemas/schema_cte.json +2793 -0
- data/data/schemas/schema_cte_os.json +1335 -0
- data/data/schemas/schema_cte_os_transporte_rodoviario.json +109 -0
- data/data/schemas/schema_cte_transporte_aereo.json +115 -0
- data/data/schemas/schema_cte_transporte_aquaviario.json +174 -0
- data/data/schemas/schema_cte_transporte_dutoviario.json +65 -0
- data/data/schemas/schema_cte_transporte_ferroviario.json +144 -0
- data/data/schemas/schema_cte_transporte_multimodal.json +45 -0
- data/data/schemas/schema_cte_transporte_rodoviario.json +78 -0
- data/data/schemas/schema_dce.json +549 -0
- data/data/schemas/schema_mdfe.json +1102 -0
- data/data/schemas/schema_mdfe_transporte_aereo.json +44 -0
- data/data/schemas/schema_mdfe_transporte_aquaviario.json +209 -0
- data/data/schemas/schema_mdfe_transporte_ferroviario.json +99 -0
- data/data/schemas/schema_mdfe_transporte_rodoviario.json +628 -0
- data/data/schemas/schema_nfcom.json +1859 -0
- data/data/schemas/schema_nfe.json +4750 -0
- data/data/schemas/schema_nfe_forma_pagamento.json +97 -0
- data/data/schemas/schema_nfe_item.json +2574 -0
- data/data/schemas/schema_nfgas.json +2316 -0
- data/data/schemas/schema_nfse_nacional.json +1847 -0
- data/data/schemas/schema_nfse_recebida.json +548 -0
- data/lib/focus_nfe/client.rb +162 -0
- data/lib/focus_nfe/configuration.rb +104 -0
- data/lib/focus_nfe/errors.rb +123 -0
- data/lib/focus_nfe/esquemas/campo.rb +171 -0
- data/lib/focus_nfe/esquemas/catalogo.rb +34 -0
- data/lib/focus_nfe/esquemas/decimal.rb +66 -0
- data/lib/focus_nfe/esquemas/esquema.rb +72 -0
- data/lib/focus_nfe/esquemas/validador.rb +87 -0
- data/lib/focus_nfe/http/adapter.rb +25 -0
- data/lib/focus_nfe/http/adapters/net_http.rb +99 -0
- data/lib/focus_nfe/http/authentication.rb +23 -0
- data/lib/focus_nfe/http/connection.rb +118 -0
- data/lib/focus_nfe/http/logging.rb +100 -0
- data/lib/focus_nfe/http/response.rb +75 -0
- data/lib/focus_nfe/modelos/documento.rb +113 -0
- data/lib/focus_nfe/modelos/inutilizacao.rb +75 -0
- data/lib/focus_nfe/modelos/pagina.rb +54 -0
- data/lib/focus_nfe/recursos/backups.rb +17 -0
- data/lib/focus_nfe/recursos/base.rb +91 -0
- data/lib/focus_nfe/recursos/ceps.rb +16 -0
- data/lib/focus_nfe/recursos/cfops.rb +16 -0
- data/lib/focus_nfe/recursos/cnaes.rb +16 -0
- data/lib/focus_nfe/recursos/cnpjs.rb +13 -0
- data/lib/focus_nfe/recursos/concerns/baixavel.rb +41 -0
- data/lib/focus_nfe/recursos/concerns/baixavel_eventos.rb +34 -0
- data/lib/focus_nfe/recursos/concerns/cancelavel.rb +25 -0
- data/lib/focus_nfe/recursos/concerns/conciliavel.rb +66 -0
- data/lib/focus_nfe/recursos/concerns/consultavel.rb +26 -0
- data/lib/focus_nfe/recursos/concerns/corrigivel.rb +45 -0
- data/lib/focus_nfe/recursos/concerns/corrigivel_cte.rb +60 -0
- data/lib/focus_nfe/recursos/concerns/emitivel.rb +51 -0
- data/lib/focus_nfe/recursos/concerns/enviavel.rb +40 -0
- data/lib/focus_nfe/recursos/concerns/eventavel.rb +46 -0
- data/lib/focus_nfe/recursos/concerns/inutilizavel.rb +96 -0
- data/lib/focus_nfe/recursos/concerns/listavel.rb +22 -0
- data/lib/focus_nfe/recursos/concerns/localizavel.rb +22 -0
- data/lib/focus_nfe/recursos/concerns/notificavel.rb +23 -0
- data/lib/focus_nfe/recursos/concerns/removivel.rb +20 -0
- data/lib/focus_nfe/recursos/concerns/visualizavel.rb +28 -0
- data/lib/focus_nfe/recursos/cte.rb +35 -0
- data/lib/focus_nfe/recursos/cte_os.rb +29 -0
- data/lib/focus_nfe/recursos/ctes_recebidas.rb +38 -0
- data/lib/focus_nfe/recursos/dce.rb +16 -0
- data/lib/focus_nfe/recursos/emails_bloqueados.rb +31 -0
- data/lib/focus_nfe/recursos/empresas.rb +35 -0
- data/lib/focus_nfe/recursos/mdfe.rb +78 -0
- data/lib/focus_nfe/recursos/municipios.rb +60 -0
- data/lib/focus_nfe/recursos/ncms.rb +16 -0
- data/lib/focus_nfe/recursos/nfce.rb +19 -0
- data/lib/focus_nfe/recursos/nfcom.rb +16 -0
- data/lib/focus_nfe/recursos/nfe.rb +106 -0
- data/lib/focus_nfe/recursos/nfes_recebidas.rb +56 -0
- data/lib/focus_nfe/recursos/nfgas.rb +16 -0
- data/lib/focus_nfe/recursos/nfse.rb +18 -0
- data/lib/focus_nfe/recursos/nfse_nacional.rb +16 -0
- data/lib/focus_nfe/recursos/nfses_nacionais_recebidas.rb +21 -0
- data/lib/focus_nfe/recursos/webhooks.rb +22 -0
- data/lib/focus_nfe/version.rb +6 -0
- data/lib/focus_nfe/webhook.rb +68 -0
- data/lib/focus_nfe.rb +124 -0
- data/sig/focus_nfe/client.rbs +38 -0
- data/sig/focus_nfe/configuration.rbs +29 -0
- data/sig/focus_nfe/errors.rbs +59 -0
- data/sig/focus_nfe/esquemas/campo.rbs +47 -0
- data/sig/focus_nfe/esquemas/catalogo.rbs +8 -0
- data/sig/focus_nfe/esquemas/decimal.rbs +25 -0
- data/sig/focus_nfe/esquemas/esquema.rbs +30 -0
- data/sig/focus_nfe/esquemas/validador.rbs +20 -0
- data/sig/focus_nfe/http/adapter.rbs +7 -0
- data/sig/focus_nfe/http/adapters/net_http.rbs +25 -0
- data/sig/focus_nfe/http/authentication.rbs +9 -0
- data/sig/focus_nfe/http/connection.rbs +32 -0
- data/sig/focus_nfe/http/logging.rbs +30 -0
- data/sig/focus_nfe/http/response.rbs +28 -0
- data/sig/focus_nfe/modelos/documento.rbs +34 -0
- data/sig/focus_nfe/modelos/inutilizacao.rbs +24 -0
- data/sig/focus_nfe/modelos/pagina.rbs +21 -0
- data/sig/focus_nfe/recursos/backups.rbs +7 -0
- data/sig/focus_nfe/recursos/base.rbs +25 -0
- data/sig/focus_nfe/recursos/ceps.rbs +10 -0
- data/sig/focus_nfe/recursos/cfops.rbs +10 -0
- data/sig/focus_nfe/recursos/cnaes.rbs +10 -0
- data/sig/focus_nfe/recursos/cnpjs.rbs +7 -0
- data/sig/focus_nfe/recursos/concerns/baixavel.rbs +12 -0
- data/sig/focus_nfe/recursos/concerns/baixavel_eventos.rbs +14 -0
- data/sig/focus_nfe/recursos/concerns/cancelavel.rbs +9 -0
- data/sig/focus_nfe/recursos/concerns/conciliavel.rbs +15 -0
- data/sig/focus_nfe/recursos/concerns/consultavel.rbs +9 -0
- data/sig/focus_nfe/recursos/concerns/corrigivel.rbs +15 -0
- data/sig/focus_nfe/recursos/concerns/corrigivel_cte.rbs +17 -0
- data/sig/focus_nfe/recursos/concerns/emitivel.rbs +14 -0
- data/sig/focus_nfe/recursos/concerns/enviavel.rbs +15 -0
- data/sig/focus_nfe/recursos/concerns/eventavel.rbs +12 -0
- data/sig/focus_nfe/recursos/concerns/inutilizavel.rbs +20 -0
- data/sig/focus_nfe/recursos/concerns/listavel.rbs +9 -0
- data/sig/focus_nfe/recursos/concerns/localizavel.rbs +9 -0
- data/sig/focus_nfe/recursos/concerns/notificavel.rbs +9 -0
- data/sig/focus_nfe/recursos/concerns/removivel.rbs +9 -0
- data/sig/focus_nfe/recursos/concerns/visualizavel.rbs +9 -0
- data/sig/focus_nfe/recursos/cte.rbs +17 -0
- data/sig/focus_nfe/recursos/cte_os.rbs +17 -0
- data/sig/focus_nfe/recursos/ctes_recebidas.rbs +14 -0
- data/sig/focus_nfe/recursos/dce.rbs +10 -0
- data/sig/focus_nfe/recursos/emails_bloqueados.rbs +12 -0
- data/sig/focus_nfe/recursos/empresas.rbs +12 -0
- data/sig/focus_nfe/recursos/mdfe.rbs +21 -0
- data/sig/focus_nfe/recursos/municipios.rbs +19 -0
- data/sig/focus_nfe/recursos/ncms.rbs +10 -0
- data/sig/focus_nfe/recursos/nfce.rbs +12 -0
- data/sig/focus_nfe/recursos/nfcom.rbs +10 -0
- data/sig/focus_nfe/recursos/nfe.rbs +23 -0
- data/sig/focus_nfe/recursos/nfes_recebidas.rbs +16 -0
- data/sig/focus_nfe/recursos/nfgas.rbs +10 -0
- data/sig/focus_nfe/recursos/nfse.rbs +11 -0
- data/sig/focus_nfe/recursos/nfse_nacional.rbs +10 -0
- data/sig/focus_nfe/recursos/nfses_nacionais_recebidas.rbs +11 -0
- data/sig/focus_nfe/recursos/webhooks.rbs +11 -0
- data/sig/focus_nfe/webhook.rbs +11 -0
- data/sig/focus_nfe.rbs +10 -0
- data/spec/focus_nfe/client_spec.rb +208 -0
- data/spec/focus_nfe/configuration_spec.rb +121 -0
- data/spec/focus_nfe/errors_mapping_spec.rb +68 -0
- data/spec/focus_nfe/errors_spec.rb +107 -0
- data/spec/focus_nfe/esquemas/campo_spec.rb +291 -0
- data/spec/focus_nfe/esquemas/decimal_spec.rb +54 -0
- data/spec/focus_nfe/esquemas/esquema_spec.rb +73 -0
- data/spec/focus_nfe/esquemas/validador_spec.rb +167 -0
- data/spec/focus_nfe/esquemas_spec.rb +42 -0
- data/spec/focus_nfe/http/adapter_spec.rb +8 -0
- data/spec/focus_nfe/http/adapters/net_http_spec.rb +181 -0
- data/spec/focus_nfe/http/authentication_spec.rb +24 -0
- data/spec/focus_nfe/http/connection_spec.rb +255 -0
- data/spec/focus_nfe/http/logging_spec.rb +83 -0
- data/spec/focus_nfe/http/response_spec.rb +161 -0
- data/spec/focus_nfe/modelos/documento_spec.rb +150 -0
- data/spec/focus_nfe/modelos/inutilizacao_spec.rb +91 -0
- data/spec/focus_nfe/modelos/pagina_spec.rb +77 -0
- data/spec/focus_nfe/recursos/backups_spec.rb +29 -0
- data/spec/focus_nfe/recursos/base_spec.rb +56 -0
- data/spec/focus_nfe/recursos/ceps_spec.rb +16 -0
- data/spec/focus_nfe/recursos/cfops_spec.rb +16 -0
- data/spec/focus_nfe/recursos/cnaes_spec.rb +20 -0
- data/spec/focus_nfe/recursos/cnpjs_spec.rb +11 -0
- data/spec/focus_nfe/recursos/concerns/emitivel_validacao_spec.rb +158 -0
- data/spec/focus_nfe/recursos/cte_os_spec.rb +9 -0
- data/spec/focus_nfe/recursos/cte_spec.rb +9 -0
- data/spec/focus_nfe/recursos/ctes_recebidas_spec.rb +56 -0
- data/spec/focus_nfe/recursos/dce_spec.rb +8 -0
- data/spec/focus_nfe/recursos/emails_bloqueados_spec.rb +29 -0
- data/spec/focus_nfe/recursos/empresas_spec.rb +45 -0
- data/spec/focus_nfe/recursos/mdfe_spec.rb +100 -0
- data/spec/focus_nfe/recursos/municipios_spec.rb +58 -0
- data/spec/focus_nfe/recursos/ncms_spec.rb +16 -0
- data/spec/focus_nfe/recursos/nfce_spec.rb +10 -0
- data/spec/focus_nfe/recursos/nfcom_spec.rb +8 -0
- data/spec/focus_nfe/recursos/nfe_spec.rb +262 -0
- data/spec/focus_nfe/recursos/nfes_recebidas_spec.rb +87 -0
- data/spec/focus_nfe/recursos/nfgas_spec.rb +8 -0
- data/spec/focus_nfe/recursos/nfse_nacional_spec.rb +8 -0
- data/spec/focus_nfe/recursos/nfse_spec.rb +9 -0
- data/spec/focus_nfe/recursos/nfses_nacionais_recebidas_spec.rb +17 -0
- data/spec/focus_nfe/recursos/webhooks_spec.rb +22 -0
- data/spec/focus_nfe/webhook_spec.rb +66 -0
- data/spec/focus_nfe_global_configuration_spec.rb +70 -0
- data/spec/focus_nfe_require_spec.rb +87 -0
- data/spec/focus_nfe_spec.rb +11 -0
- data/spec/spec_helper.rb +58 -0
- data/spec/support/shared_examples/recurso_fiscal.rb +445 -0
- data/spec/support/shared_examples/recurso_leitura.rb +217 -0
- data/tools/pull_fields.rb +62 -0
- 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
data/.yardopts
ADDED
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`.
|
data/CODE_OF_CONDUCT.md
ADDED
|
@@ -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.
|