nfcom 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 +7 -0
- data/.rubocop.yml +115 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +66 -0
- data/LICENSE +21 -0
- data/README.md +280 -0
- data/Rakefile +22 -0
- data/examples/.env.example +41 -0
- data/examples/emitir_nota.rb +91 -0
- data/examples/rails_initializer.rb +72 -0
- data/lib/nfcom/builder/danfe_com.rb +564 -0
- data/lib/nfcom/builder/qrcode.rb +68 -0
- data/lib/nfcom/builder/signature.rb +156 -0
- data/lib/nfcom/builder/xml_builder.rb +362 -0
- data/lib/nfcom/client.rb +106 -0
- data/lib/nfcom/configuration.rb +134 -0
- data/lib/nfcom/errors.rb +27 -0
- data/lib/nfcom/helpers/consulta.rb +28 -0
- data/lib/nfcom/models/assinante.rb +146 -0
- data/lib/nfcom/models/destinatario.rb +138 -0
- data/lib/nfcom/models/emitente.rb +105 -0
- data/lib/nfcom/models/endereco.rb +123 -0
- data/lib/nfcom/models/fatura/codigo_de_barras/formato_44.rb +52 -0
- data/lib/nfcom/models/fatura/codigo_de_barras.rb +57 -0
- data/lib/nfcom/models/fatura.rb +172 -0
- data/lib/nfcom/models/item.rb +353 -0
- data/lib/nfcom/models/nota.rb +398 -0
- data/lib/nfcom/models/total.rb +60 -0
- data/lib/nfcom/parsers/autorizacao.rb +28 -0
- data/lib/nfcom/parsers/base.rb +30 -0
- data/lib/nfcom/parsers/consulta.rb +34 -0
- data/lib/nfcom/parsers/inutilizacao.rb +23 -0
- data/lib/nfcom/parsers/status.rb +23 -0
- data/lib/nfcom/utils/certificate.rb +109 -0
- data/lib/nfcom/utils/compressor.rb +47 -0
- data/lib/nfcom/utils/helpers.rb +141 -0
- data/lib/nfcom/utils/response_decompressor.rb +47 -0
- data/lib/nfcom/utils/xml_authorized.rb +29 -0
- data/lib/nfcom/utils/xml_cleaner.rb +68 -0
- data/lib/nfcom/validators/business_rules.rb +45 -0
- data/lib/nfcom/validators/schema_validator.rb +316 -0
- data/lib/nfcom/validators/xml_validator.rb +29 -0
- data/lib/nfcom/version.rb +5 -0
- data/lib/nfcom/webservices/autorizacao.rb +36 -0
- data/lib/nfcom/webservices/base.rb +96 -0
- data/lib/nfcom/webservices/consulta.rb +59 -0
- data/lib/nfcom/webservices/inutilizacao.rb +71 -0
- data/lib/nfcom/webservices/status.rb +64 -0
- data/lib/nfcom.rb +98 -0
- data/nfcom.gemspec +42 -0
- metadata +242 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: f32a81ac2b024665327e6649dd7ce8003210074349a587ac94e59da097292304
|
|
4
|
+
data.tar.gz: 382c3ef2e2932b82bff36c7523e7612408ef728839f003944cd7e291ea944ffa
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: cbab82c83610bcd0bf2cd28dade2fb53cacce091120eb2c6d7c9ac38908d6969fa7f2ebbe4a02a11eebc87936ab98e9b41cd584d33351c9f97332e0ddee5b48d
|
|
7
|
+
data.tar.gz: 139211d3998a511a8a32e6ee49d688846b1ff79bd2cdfe0b103fbfc83e7beae9aac94633c51c23cc80508db4c31db45ea8b8e2491f00f9cc83bfbc337c7b9c95
|
data/.rubocop.yml
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
require:
|
|
2
|
+
- rubocop-rspec
|
|
3
|
+
|
|
4
|
+
AllCops:
|
|
5
|
+
TargetRubyVersion: 2.7
|
|
6
|
+
NewCops: enable
|
|
7
|
+
Exclude:
|
|
8
|
+
- 'vendor/**/*'
|
|
9
|
+
- 'tmp/**/*'
|
|
10
|
+
- 'node_modules/**/*'
|
|
11
|
+
- 'bin/**/*'
|
|
12
|
+
|
|
13
|
+
# Configurações de estilo
|
|
14
|
+
|
|
15
|
+
Style/Documentation:
|
|
16
|
+
Enabled: false
|
|
17
|
+
|
|
18
|
+
Style/StringLiterals:
|
|
19
|
+
Enabled: true
|
|
20
|
+
EnforcedStyle: single_quotes
|
|
21
|
+
|
|
22
|
+
Style/FrozenStringLiteralComment:
|
|
23
|
+
Enabled: true
|
|
24
|
+
EnforcedStyle: always
|
|
25
|
+
|
|
26
|
+
# Métricas
|
|
27
|
+
|
|
28
|
+
Metrics/BlockLength:
|
|
29
|
+
Exclude:
|
|
30
|
+
- 'spec/**/*'
|
|
31
|
+
- 'examples/**/*'
|
|
32
|
+
|
|
33
|
+
Metrics/MethodLength:
|
|
34
|
+
Max: 25
|
|
35
|
+
Exclude:
|
|
36
|
+
- 'spec/**/*'
|
|
37
|
+
- 'lib/nfcom/builder/**/*' # Builders naturalmente têm métodos longos para gerar XML
|
|
38
|
+
|
|
39
|
+
Metrics/ClassLength:
|
|
40
|
+
Max: 150
|
|
41
|
+
Exclude:
|
|
42
|
+
- 'lib/nfcom/builder/**/*' # Builders podem ser mais longos
|
|
43
|
+
|
|
44
|
+
Metrics/ModuleLength:
|
|
45
|
+
Max: 150
|
|
46
|
+
|
|
47
|
+
Metrics/AbcSize:
|
|
48
|
+
Max: 25 # Aumentado para permitir validações complexas
|
|
49
|
+
Exclude:
|
|
50
|
+
- 'spec/**/*'
|
|
51
|
+
- 'lib/nfcom/builder/**/*' # Builders têm alta complexidade por gerarem XML
|
|
52
|
+
AllowedMethods:
|
|
53
|
+
- erros # Métodos de validação naturalmente complexos
|
|
54
|
+
- initialize # Construtores podem ser complexos
|
|
55
|
+
|
|
56
|
+
Metrics/CyclomaticComplexity:
|
|
57
|
+
Max: 10 # Validações têm muitas condições
|
|
58
|
+
AllowedMethods:
|
|
59
|
+
- erros
|
|
60
|
+
- initialize
|
|
61
|
+
|
|
62
|
+
Metrics/PerceivedComplexity:
|
|
63
|
+
Max: 10 # Validações têm muitas condições
|
|
64
|
+
AllowedMethods:
|
|
65
|
+
- erros
|
|
66
|
+
- initialize
|
|
67
|
+
|
|
68
|
+
# Layout
|
|
69
|
+
|
|
70
|
+
Layout/LineLength:
|
|
71
|
+
Max: 120
|
|
72
|
+
Exclude:
|
|
73
|
+
- 'spec/**/*'
|
|
74
|
+
|
|
75
|
+
Layout/MultilineMethodCallIndentation:
|
|
76
|
+
EnforcedStyle: indented
|
|
77
|
+
|
|
78
|
+
# Naming
|
|
79
|
+
|
|
80
|
+
Naming/VariableNumber:
|
|
81
|
+
Enabled: false
|
|
82
|
+
|
|
83
|
+
Naming/MethodParameterName:
|
|
84
|
+
MinNameLength: 2
|
|
85
|
+
|
|
86
|
+
# Lint
|
|
87
|
+
|
|
88
|
+
Lint/MissingSuper:
|
|
89
|
+
Enabled: false
|
|
90
|
+
|
|
91
|
+
# RSpec
|
|
92
|
+
|
|
93
|
+
RSpec/ExampleLength:
|
|
94
|
+
Max: 20
|
|
95
|
+
|
|
96
|
+
RSpec/MultipleExpectations:
|
|
97
|
+
Max: 5
|
|
98
|
+
|
|
99
|
+
RSpec/NestedGroups:
|
|
100
|
+
Max: 5
|
|
101
|
+
|
|
102
|
+
RSpec/MultipleMemoizedHelpers:
|
|
103
|
+
Max: 10
|
|
104
|
+
|
|
105
|
+
# Suporte para contextos em português
|
|
106
|
+
RSpec/ContextWording:
|
|
107
|
+
Prefixes:
|
|
108
|
+
- when
|
|
109
|
+
- with
|
|
110
|
+
- without
|
|
111
|
+
- com # "com" = "with" em português
|
|
112
|
+
- quando # "quando" = "when" em português
|
|
113
|
+
- sem # "sem" = "without" em português
|
|
114
|
+
- para # "para" = "for" em português
|
|
115
|
+
- dado # "dado" = "given" em português
|
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.3.4
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.1.0] - 2025-12-30
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- Estrutura inicial da gem
|
|
14
|
+
- Configuração básica via `Nfcom.configure`
|
|
15
|
+
- Modelos: Nota, Emitente, Destinatario, Item, Total, Endereco
|
|
16
|
+
- Builder de XML conforme layout NF-COM 1.00
|
|
17
|
+
- Assinatura digital com certificado A1/A3
|
|
18
|
+
- Validação de CNPJ, CPF e CEP
|
|
19
|
+
- Webservices SOAP para:
|
|
20
|
+
- Autorização de notas
|
|
21
|
+
- Consulta de notas
|
|
22
|
+
- Status do serviço
|
|
23
|
+
- Inutilização de numeração
|
|
24
|
+
- Parser de respostas da SEFAZ
|
|
25
|
+
- Validador de XML
|
|
26
|
+
- Validador de regras de negócio
|
|
27
|
+
- Geração de chave de acesso
|
|
28
|
+
- Geração de URL para QR Code
|
|
29
|
+
- Retry automático em caso de falhas
|
|
30
|
+
- Tratamento de erros específicos
|
|
31
|
+
- Helper utilities
|
|
32
|
+
- Gerenciador de certificado digital
|
|
33
|
+
- Suporte a ambiente de homologação e produção
|
|
34
|
+
- Suporte inicial para PE (Pernambuco)
|
|
35
|
+
- Documentação completa
|
|
36
|
+
- Exemplos de uso
|
|
37
|
+
- Testes RSpec (estrutura)
|
|
38
|
+
|
|
39
|
+
### Notes
|
|
40
|
+
- Versão inicial (MVP)
|
|
41
|
+
- Suporte apenas para Pernambuco no momento
|
|
42
|
+
- Validação XSD será implementada em versão futura
|
|
43
|
+
- Contingência (FS-DA) será implementada em versão futura
|
|
44
|
+
- Cancelamento será implementado em versão futura
|
|
45
|
+
|
|
46
|
+
## [0.1.1] - 2026-01-15
|
|
47
|
+
|
|
48
|
+
### Added
|
|
49
|
+
- Gerador de DANFE-COM em PDF via Prawn (`Nfcom::DanfeCom`)
|
|
50
|
+
- Layout completo: cabeçalho, emitente, destinatário, itens, totais, fatura
|
|
51
|
+
- Exibição do período de uso do serviço (`dPerUsoIni` / `dPerUsoFim`)
|
|
52
|
+
- Banner do Simples Nacional quando `CRT = 1`
|
|
53
|
+
- Suporte a logotipo (PNG e SVG via prawn-svg)
|
|
54
|
+
- Formatação de código de barras e exibição de QR Code
|
|
55
|
+
- Layout dinâmico adaptável ao conteúdo
|
|
56
|
+
- Gerador de código de barras (`Nfcom::Models::Fatura::CodigoDeBarras`)
|
|
57
|
+
- Modelo `Formato44` para representação da linha digitável
|
|
58
|
+
|
|
59
|
+
## [0.1.2] - 2026-03-31
|
|
60
|
+
|
|
61
|
+
### Added
|
|
62
|
+
- Suporte a notas de substituição (`finalidade: :substituicao`)
|
|
63
|
+
- Atributos `chave_nfcom_substituida` e `motivo_substituicao` no modelo `Nota`
|
|
64
|
+
- Geração do grupo `gSub` no XML (`chNFCom` + `motSub`) conforme schema NFCom v1.00
|
|
65
|
+
- Validação de presença e formato da chave substituída (44 dígitos) e do motivo (D26)
|
|
66
|
+
- Todos os 5 motivos de substituição suportados: erro de preço, erro cadastral, decisão judicial, erro de tributação e descontinuidade do serviço
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Keith Yoder
|
|
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 all
|
|
13
|
+
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 THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,280 @@
|
|
|
1
|
+
# Nfcom Ruby
|
|
2
|
+
|
|
3
|
+
[](https://github.com/keithyoder/nfcom-ruby/actions/workflows/ci.yml)
|
|
4
|
+
[](https://github.com/keithyoder/nfcom-ruby/actions/workflows/security.yml)
|
|
5
|
+
[](https://badge.fury.io/rb/nfcom)
|
|
6
|
+
|
|
7
|
+
Biblioteca Ruby para emissão de NF-COM (Nota Fiscal de Comunicação) modelo 62, desenvolvida especialmente para provedores de internet e empresas de telecomunicação.
|
|
8
|
+
|
|
9
|
+
## Características
|
|
10
|
+
|
|
11
|
+
- ✅ Emissão de NF-COM modelo 62
|
|
12
|
+
- ✅ Assinatura digital com certificado A1/A3
|
|
13
|
+
- ✅ Integração com SEFAZ via webservices SOAP
|
|
14
|
+
- ✅ Validação de XML e regras de negócio
|
|
15
|
+
- ✅ Suporte a ambiente de homologação e produção
|
|
16
|
+
- ✅ Retry automático em caso de falhas
|
|
17
|
+
- ✅ Geração de QR Code para consulta
|
|
18
|
+
- ✅ Consulta de notas autorizadas
|
|
19
|
+
- ✅ Verificação de status da SEFAZ
|
|
20
|
+
- ✅ Inutilização de numeração
|
|
21
|
+
|
|
22
|
+
## Instalação
|
|
23
|
+
|
|
24
|
+
Adicione ao seu Gemfile:
|
|
25
|
+
|
|
26
|
+
```ruby
|
|
27
|
+
gem 'nfcom'
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Ou instale diretamente:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
gem install nfcom
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Configuração
|
|
37
|
+
|
|
38
|
+
```ruby
|
|
39
|
+
require 'nfcom'
|
|
40
|
+
|
|
41
|
+
Nfcom.configure do |config|
|
|
42
|
+
# Ambiente
|
|
43
|
+
config.ambiente = :homologacao # ou :producao
|
|
44
|
+
config.estado = 'PE'
|
|
45
|
+
|
|
46
|
+
# Certificado digital
|
|
47
|
+
config.certificado_path = '/path/to/certificado.pfx'
|
|
48
|
+
config.certificado_senha = 'senha_do_certificado'
|
|
49
|
+
|
|
50
|
+
# Dados do emitente
|
|
51
|
+
config.cnpj = '12345678000100'
|
|
52
|
+
config.razao_social = 'Minha Empresa LTDA'
|
|
53
|
+
config.inscricao_estadual = '0123456789'
|
|
54
|
+
config.regime_tributario = :simples_nacional
|
|
55
|
+
|
|
56
|
+
# Configurações opcionais
|
|
57
|
+
config.serie_padrao = 1
|
|
58
|
+
config.timeout = 30
|
|
59
|
+
config.max_tentativas = 3
|
|
60
|
+
config.log_level = :info
|
|
61
|
+
end
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Uso Básico
|
|
65
|
+
|
|
66
|
+
### Emitir uma Nota
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
# 1. Criar a nota
|
|
70
|
+
nota = Nfcom::Models::Nota.new do |n|
|
|
71
|
+
n.serie = 1
|
|
72
|
+
n.numero = 1
|
|
73
|
+
|
|
74
|
+
# Emitente
|
|
75
|
+
n.emitente = Nfcom::Models::Emitente.new(
|
|
76
|
+
cnpj: '12345678000100',
|
|
77
|
+
razao_social: 'Provedor Internet LTDA',
|
|
78
|
+
nome_fantasia: 'Meu Provedor',
|
|
79
|
+
inscricao_estadual: '0123456789',
|
|
80
|
+
endereco: {
|
|
81
|
+
logradouro: 'Rua das Flores',
|
|
82
|
+
numero: '123',
|
|
83
|
+
bairro: 'Centro',
|
|
84
|
+
codigo_municipio: '2611606',
|
|
85
|
+
municipio: 'Recife',
|
|
86
|
+
uf: 'PE',
|
|
87
|
+
cep: '50000-000'
|
|
88
|
+
}
|
|
89
|
+
)
|
|
90
|
+
|
|
91
|
+
# Destinatário (cliente)
|
|
92
|
+
n.destinatario = Nfcom::Models::Destinatario.new(
|
|
93
|
+
cpf: '12345678900',
|
|
94
|
+
razao_social: 'Cliente Pessoa Física',
|
|
95
|
+
tipo_assinante: :residencial,
|
|
96
|
+
email: 'cliente@email.com',
|
|
97
|
+
endereco: {
|
|
98
|
+
logradouro: 'Av. Principal',
|
|
99
|
+
numero: '456',
|
|
100
|
+
bairro: 'Jardins',
|
|
101
|
+
codigo_municipio: '2611606',
|
|
102
|
+
municipio: 'Recife',
|
|
103
|
+
uf: 'PE',
|
|
104
|
+
cep: '51000-000'
|
|
105
|
+
}
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# Fatura
|
|
109
|
+
n.fatura = Nfcom::Models::Fatura.new(
|
|
110
|
+
competencia: '202601', # AAAAMM
|
|
111
|
+
data_vencimento: '2026-02-15', # YYYY-MM-DD
|
|
112
|
+
codigo_barras: '23793381286000000099901234567890123456789012',
|
|
113
|
+
valor_fatura: 99.90
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
# Adicionar serviço (item)
|
|
117
|
+
n.add_item(
|
|
118
|
+
codigo_servico: '0303', # Internet
|
|
119
|
+
descricao: 'Plano Fibra 100MB',
|
|
120
|
+
classe_consumo: :nao_medido_internet, # Usar símbolo do enum
|
|
121
|
+
cfop: '5307', # Prestação de serviço de comunicação
|
|
122
|
+
unidade: :un, # Usar símbolo
|
|
123
|
+
quantidade: 1,
|
|
124
|
+
valor_unitario: 99.90
|
|
125
|
+
)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# 2. Enviar para SEFAZ
|
|
129
|
+
client = Nfcom::Client.new
|
|
130
|
+
resultado = client.autorizar(nota)
|
|
131
|
+
|
|
132
|
+
if resultado[:autorizada]
|
|
133
|
+
puts "✓ Nota autorizada!"
|
|
134
|
+
puts "Chave: #{nota.chave_acesso}"
|
|
135
|
+
puts "Protocolo: #{nota.protocolo}"
|
|
136
|
+
puts "Data: #{nota.data_autorizacao}"
|
|
137
|
+
|
|
138
|
+
# Salvar XML autorizado completo (nfcomProc)
|
|
139
|
+
# Este XML contém a NFCom assinada + protocolo de autorização
|
|
140
|
+
xml_completo = nota.xml_autorizado
|
|
141
|
+
File.write("nfcom_#{nota.numero}_#{nota.protocolo}.xml", xml_completo)
|
|
142
|
+
|
|
143
|
+
# Ou salvar com formatação bonita
|
|
144
|
+
doc = Nokogiri::XML(xml_completo)
|
|
145
|
+
File.write("nfcom_#{nota.numero}.xml", doc.to_xml(indent: 2))
|
|
146
|
+
|
|
147
|
+
puts "✓ XML salvo com sucesso"
|
|
148
|
+
else
|
|
149
|
+
puts "✗ Erro na autorização"
|
|
150
|
+
puts "Código: #{resultado[:codigo]}"
|
|
151
|
+
puts "Motivo: #{resultado[:motivo]}"
|
|
152
|
+
end
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
### O que é armazenado após autorização
|
|
156
|
+
|
|
157
|
+
Após a autorização bem-sucedida, o objeto `nota` é atualizado com:
|
|
158
|
+
|
|
159
|
+
```ruby
|
|
160
|
+
nota.chave_acesso # "26260107159053000107620010000081661049503004"
|
|
161
|
+
nota.protocolo # "3262600000362421"
|
|
162
|
+
nota.data_autorizacao # "2026-01-16T06:29:46-03:00"
|
|
163
|
+
nota.xml_autorizado # XML completo (nfcomProc)
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
O `nota.xml_autorizado` contém o documento completo no formato `nfcomProc`:
|
|
167
|
+
- A NFCom original assinada (`<NFCom>` com `<Signature>`)
|
|
168
|
+
- O protocolo de autorização da SEFAZ (`<protNFCom>`)
|
|
169
|
+
|
|
170
|
+
Este é o XML legalmente válido que deve ser armazenado e fornecido ao cliente.
|
|
171
|
+
|
|
172
|
+
### Consultando uma Nota
|
|
173
|
+
|
|
174
|
+
```ruby
|
|
175
|
+
client = Nfcom::Client.new
|
|
176
|
+
|
|
177
|
+
resultado = client.consultar_nota(
|
|
178
|
+
chave: '26220512345678000100620010000000011234567890'
|
|
179
|
+
)
|
|
180
|
+
|
|
181
|
+
puts "Situação: #{resultado[:situacao]}"
|
|
182
|
+
puts "Protocolo: #{resultado[:protocolo]}"
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
### Verificando Status da SEFAZ
|
|
186
|
+
|
|
187
|
+
```ruby
|
|
188
|
+
client = Nfcom::Client.new
|
|
189
|
+
status = client.status_servico
|
|
190
|
+
|
|
191
|
+
if status[:online]
|
|
192
|
+
puts "✓ SEFAZ online"
|
|
193
|
+
puts "Tempo médio de resposta: #{status[:tempo_medio]}ms"
|
|
194
|
+
else
|
|
195
|
+
puts "✗ SEFAZ offline: #{status[:motivo]}"
|
|
196
|
+
end
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Inutilizando Numeração
|
|
200
|
+
|
|
201
|
+
```ruby
|
|
202
|
+
client = Nfcom::Client.new
|
|
203
|
+
|
|
204
|
+
resultado = client.inutilizar(
|
|
205
|
+
serie: 1,
|
|
206
|
+
numero_inicial: 10,
|
|
207
|
+
numero_final: 15,
|
|
208
|
+
justificativa: 'Inutilização de numeração por erro no sistema'
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
if resultado[:inutilizada]
|
|
212
|
+
puts "✓ Numeração inutilizada"
|
|
213
|
+
puts "Protocolo: #{resultado[:protocolo]}"
|
|
214
|
+
end
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Ambiente de Homologação
|
|
218
|
+
|
|
219
|
+
Durante o desenvolvimento, sempre use o ambiente de homologação:
|
|
220
|
+
|
|
221
|
+
```ruby
|
|
222
|
+
Nfcom.configure do |config|
|
|
223
|
+
config.ambiente = :homologacao
|
|
224
|
+
# ... outras configurações
|
|
225
|
+
end
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
## Desenvolvimento
|
|
229
|
+
|
|
230
|
+
```bash
|
|
231
|
+
# Instalar dependências
|
|
232
|
+
bundle install
|
|
233
|
+
|
|
234
|
+
# Rodar testes
|
|
235
|
+
bundle exec rspec
|
|
236
|
+
|
|
237
|
+
# Rodar linter
|
|
238
|
+
bundle exec rubocop
|
|
239
|
+
|
|
240
|
+
# Console interativo
|
|
241
|
+
bundle exec irb -r ./lib/nfcom
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
## Contribuindo
|
|
245
|
+
|
|
246
|
+
1. Fork o projeto
|
|
247
|
+
2. Crie uma branch para sua feature (`git checkout -b feature/nova-funcionalidade`)
|
|
248
|
+
3. Commit suas mudanças (`git commit -am 'Adiciona nova funcionalidade'`)
|
|
249
|
+
4. Push para a branch (`git push origin feature/nova-funcionalidade`)
|
|
250
|
+
5. Crie um Pull Request
|
|
251
|
+
|
|
252
|
+
## Licença
|
|
253
|
+
|
|
254
|
+
MIT License - veja [LICENSE](LICENSE) para detalhes.
|
|
255
|
+
|
|
256
|
+
## Suporte
|
|
257
|
+
|
|
258
|
+
- GitHub Issues: https://github.com/keithyoder/nfcom-ruby/issues
|
|
259
|
+
- Documentação SEFAZ: http://www.nfcom.fazenda.gov.br/
|
|
260
|
+
- Manual NFCom: [Portal da Nota Fiscal](http://www.nfcom.fazenda.gov.br/)
|
|
261
|
+
|
|
262
|
+
## Roadmap
|
|
263
|
+
|
|
264
|
+
- [x] Emissão de NFCom
|
|
265
|
+
- [x] Assinatura digital
|
|
266
|
+
- [x] Integração SEFAZ
|
|
267
|
+
- [x] Consulta de notas
|
|
268
|
+
- [x] Validações completas
|
|
269
|
+
- [ ] Geração de DANFE-COM (PDF)
|
|
270
|
+
- [ ] Suporte a mais estados (atualmente PE)
|
|
271
|
+
- [ ] Contingência (FS-DA)
|
|
272
|
+
- [ ] Cancelamento de notas
|
|
273
|
+
- [ ] Carta de correção
|
|
274
|
+
- [ ] Validação contra schemas XSD
|
|
275
|
+
- [ ] Cache de consultas
|
|
276
|
+
- [ ] Webhook para eventos
|
|
277
|
+
|
|
278
|
+
## Autores
|
|
279
|
+
|
|
280
|
+
- Keith Yoder - Desenvolvedor inicial
|
data/Rakefile
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'bundler/gem_tasks'
|
|
4
|
+
require 'rspec/core/rake_task'
|
|
5
|
+
|
|
6
|
+
RSpec::Core::RakeTask.new(:spec)
|
|
7
|
+
|
|
8
|
+
require 'rubocop/rake_task'
|
|
9
|
+
|
|
10
|
+
RuboCop::RakeTask.new
|
|
11
|
+
|
|
12
|
+
# Bundler Audit task
|
|
13
|
+
desc 'Run bundler-audit to check for vulnerable dependencies'
|
|
14
|
+
task :audit do
|
|
15
|
+
require 'bundler/audit/cli'
|
|
16
|
+
Bundler::Audit::CLI.start(['check', '--update'])
|
|
17
|
+
rescue LoadError
|
|
18
|
+
warn 'bundler-audit not available. Install it with: gem install bundler-audit'
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
task default: %i[spec rubocop]
|
|
22
|
+
task ci: %i[spec rubocop audit]
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# ============================================
|
|
2
|
+
# CONFIGURAÇÃO NFCOM - Nota Fiscal de Comunicação
|
|
3
|
+
# ============================================
|
|
4
|
+
# Copie este arquivo para .env e preencha com seus dados reais
|
|
5
|
+
# NUNCA commite o arquivo .env no Git!
|
|
6
|
+
|
|
7
|
+
# ============================================
|
|
8
|
+
# CERTIFICADO DIGITAL (OBRIGATÓRIO)
|
|
9
|
+
# ============================================
|
|
10
|
+
# Caminho completo para o arquivo .pfx ou .p12
|
|
11
|
+
NFCOM_CERTIFICADO_PATH=/caminho/completo/para/certificado.pfx
|
|
12
|
+
|
|
13
|
+
# Senha do certificado digital
|
|
14
|
+
NFCOM_CERTIFICADO_SENHA=senha_do_certificado
|
|
15
|
+
|
|
16
|
+
# ============================================
|
|
17
|
+
# DADOS DO EMITENTE (OBRIGATÓRIO)
|
|
18
|
+
# ============================================
|
|
19
|
+
# Seus dados cadastrais como provedor de internet
|
|
20
|
+
NFCOM_CNPJ=12345678000100
|
|
21
|
+
NFCOM_RAZAO_SOCIAL=Minha Empresa LTDA
|
|
22
|
+
NFCOM_INSCRICAO_ESTADUAL=0123456789
|
|
23
|
+
|
|
24
|
+
# Regime Tributário
|
|
25
|
+
# 1 = Simples Nacional (padrão)
|
|
26
|
+
# 3 = Regime Normal
|
|
27
|
+
NFCOM_REGIME_TRIBUTARIO=1
|
|
28
|
+
|
|
29
|
+
# ============================================
|
|
30
|
+
# CONFIGURAÇÕES OPCIONAIS
|
|
31
|
+
# ============================================
|
|
32
|
+
# Série da nota fiscal (padrão: 1)
|
|
33
|
+
NFCOM_SERIE_PADRAO=1
|
|
34
|
+
|
|
35
|
+
# ============================================
|
|
36
|
+
# NOTAS IMPORTANTES
|
|
37
|
+
# ============================================
|
|
38
|
+
# 1. Este arquivo deve estar em .gitignore
|
|
39
|
+
# 2. NUNCA commite certificados ou senhas
|
|
40
|
+
# 3. Para produção, use variáveis de ambiente do servidor
|
|
41
|
+
# 4. Sempre teste em homologação primeiro
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'nfcom'
|
|
4
|
+
|
|
5
|
+
# Configuração
|
|
6
|
+
Nfcom.configure do |config|
|
|
7
|
+
config.ambiente = :homologacao
|
|
8
|
+
config.estado = 'PE'
|
|
9
|
+
config.certificado_path = 'caminho/para/certificado.pfx'
|
|
10
|
+
config.certificado_senha = 'senha'
|
|
11
|
+
config.cnpj = '12345678000100'
|
|
12
|
+
config.razao_social = 'Provedor Internet LTDA'
|
|
13
|
+
config.inscricao_estadual = '0123456789'
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# Criar nota
|
|
17
|
+
nota = Nfcom::Models::Nota.new do |n|
|
|
18
|
+
n.serie = 1
|
|
19
|
+
n.numero = 1
|
|
20
|
+
|
|
21
|
+
# Emitente
|
|
22
|
+
n.emitente = Nfcom::Models::Emitente.new(
|
|
23
|
+
cnpj: '12345678000100',
|
|
24
|
+
razao_social: 'Provedor Internet LTDA',
|
|
25
|
+
nome_fantasia: 'Meu Provedor',
|
|
26
|
+
inscricao_estadual: '0123456789',
|
|
27
|
+
endereco: {
|
|
28
|
+
logradouro: 'Rua das Flores',
|
|
29
|
+
numero: '123',
|
|
30
|
+
bairro: 'Centro',
|
|
31
|
+
codigo_municipio: '2611606',
|
|
32
|
+
municipio: 'Recife',
|
|
33
|
+
uf: 'PE',
|
|
34
|
+
cep: '50000-000'
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
# Destinatário
|
|
39
|
+
n.destinatario = Nfcom::Models::Destinatario.new(
|
|
40
|
+
cpf: '12345678900',
|
|
41
|
+
razao_social: 'Cliente Teste',
|
|
42
|
+
tipo_assinante: :residencial,
|
|
43
|
+
email: 'cliente@teste.com',
|
|
44
|
+
endereco: {
|
|
45
|
+
logradouro: 'Av. Principal',
|
|
46
|
+
numero: '456',
|
|
47
|
+
bairro: 'Jardins',
|
|
48
|
+
codigo_municipio: '2611606',
|
|
49
|
+
municipio: 'Recife',
|
|
50
|
+
uf: 'PE',
|
|
51
|
+
cep: '51000-000'
|
|
52
|
+
}
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
# Adicionar item
|
|
56
|
+
n.add_item(
|
|
57
|
+
codigo_servico: '0303',
|
|
58
|
+
descricao: 'Plano Fibra 100MB',
|
|
59
|
+
classe_consumo: '0303',
|
|
60
|
+
cfop: '5307',
|
|
61
|
+
quantidade: 1,
|
|
62
|
+
valor_unitario: 99.90
|
|
63
|
+
)
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# Validar nota
|
|
67
|
+
if nota.valida?
|
|
68
|
+
puts '✓ Nota válida'
|
|
69
|
+
|
|
70
|
+
# Emitir nota
|
|
71
|
+
begin
|
|
72
|
+
client = Nfcom::Client.new
|
|
73
|
+
resultado = client.autorizar(nota)
|
|
74
|
+
|
|
75
|
+
if resultado[:autorizada]
|
|
76
|
+
puts '✓ Nota autorizada!'
|
|
77
|
+
puts " Chave: #{resultado[:chave]}"
|
|
78
|
+
puts " Protocolo: #{resultado[:protocolo]}"
|
|
79
|
+
puts " Data: #{resultado[:data_autorizacao]}"
|
|
80
|
+
end
|
|
81
|
+
rescue Nfcom::Errors::NotaRejeitada => e
|
|
82
|
+
puts "✗ Nota rejeitada [#{e.codigo}]: #{e.motivo}"
|
|
83
|
+
rescue Nfcom::Errors::SefazIndisponivel
|
|
84
|
+
puts '✗ SEFAZ temporariamente indisponível'
|
|
85
|
+
rescue StandardError => e
|
|
86
|
+
puts "✗ Erro: #{e.message}"
|
|
87
|
+
end
|
|
88
|
+
else
|
|
89
|
+
puts '✗ Nota inválida:'
|
|
90
|
+
nota.erros.each { |erro| puts " - #{erro}" }
|
|
91
|
+
end
|