br_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/Gemfile +15 -0
- data/Gemfile.lock +169 -0
- data/LICENSE +20 -0
- data/README.markdown +6 -0
- data/Rakefile +13 -0
- data/br_nfe.gemspec +28 -0
- data/lib/br_nfe/active_model_base.rb +62 -0
- data/lib/br_nfe/base.rb +168 -0
- data/lib/br_nfe/condicao_pagamento.rb +26 -0
- data/lib/br_nfe/destinatario.rb +26 -0
- data/lib/br_nfe/emitente.rb +40 -0
- data/lib/br_nfe/endereco.rb +44 -0
- data/lib/br_nfe/helper/cpf_cnpj.rb +60 -0
- data/lib/br_nfe/helper/have_address.rb +29 -0
- data/lib/br_nfe/helper/have_condicao_pagamento.rb +24 -0
- data/lib/br_nfe/helper/have_destinatario.rb +18 -0
- data/lib/br_nfe/helper/have_emitente.rb +20 -0
- data/lib/br_nfe/helper/have_intermediario.rb +24 -0
- data/lib/br_nfe/helper/have_rps.rb +27 -0
- data/lib/br_nfe/helper/string_methods.rb +21 -0
- data/lib/br_nfe/seed.rb +195 -0
- data/lib/br_nfe/servico/base.rb +35 -0
- data/lib/br_nfe/servico/betha/base.rb +74 -0
- data/lib/br_nfe/servico/betha/v1/build_response.rb +219 -0
- data/lib/br_nfe/servico/betha/v1/cancelamento_nfs.rb +52 -0
- data/lib/br_nfe/servico/betha/v1/consulta_lote_rps.rb +31 -0
- data/lib/br_nfe/servico/betha/v1/consulta_nfs_por_rps.rb +34 -0
- data/lib/br_nfe/servico/betha/v1/consulta_nfse.rb +50 -0
- data/lib/br_nfe/servico/betha/v1/consulta_situacao_lote_rps.rb +18 -0
- data/lib/br_nfe/servico/betha/v1/gateway.rb +115 -0
- data/lib/br_nfe/servico/betha/v1/recepcao_lote_rps.rb +89 -0
- data/lib/br_nfe/servico/betha/v2/cancelamento_nfs.rb +25 -0
- data/lib/br_nfe/servico/betha/v2/consulta_lote_rps.rb +27 -0
- data/lib/br_nfe/servico/betha/v2/consulta_nfse_por_rps.rb +27 -0
- data/lib/br_nfe/servico/betha/v2/envio_lote_rps_sincrono.rb +26 -0
- data/lib/br_nfe/servico/betha/v2/gateway.rb +198 -0
- data/lib/br_nfe/servico/betha/v2/gera_nfse.rb +25 -0
- data/lib/br_nfe/servico/betha/v2/recepcao_lote_rps.rb +47 -0
- data/lib/br_nfe/servico/betha/v2/response.rb +23 -0
- data/lib/br_nfe/servico/betha/v2/substituicao_nfse.rb +39 -0
- data/lib/br_nfe/servico/intermediario.rb +17 -0
- data/lib/br_nfe/servico/response/default.rb +34 -0
- data/lib/br_nfe/servico/response/nota_fiscal.rb +73 -0
- data/lib/br_nfe/servico/rps.rb +103 -0
- data/lib/br_nfe/version.rb +8 -0
- data/lib/br_nfe.rb +146 -0
- data/test/br_nfe/base_test.rb +274 -0
- data/test/br_nfe/condicao_pagamento_test.rb +23 -0
- data/test/br_nfe/destinatario_test.rb +26 -0
- data/test/br_nfe/emitente_test.rb +26 -0
- data/test/br_nfe/endereco_test.rb +50 -0
- data/test/br_nfe/helper/have_address_test.rb +62 -0
- data/test/br_nfe/helper/have_condicao_pagamento_test.rb +71 -0
- data/test/br_nfe/helper/have_destinatario_test.rb +64 -0
- data/test/br_nfe/helper/have_emitente_test.rb +63 -0
- data/test/br_nfe/helper/have_intermediario_test.rb +77 -0
- data/test/br_nfe/helper/have_rps_test.rb +59 -0
- data/test/br_nfe/servico/base_test.rb +23 -0
- data/test/br_nfe/servico/betha/base_test.rb +106 -0
- data/test/br_nfe/servico/betha/v1/build_response_test.rb +558 -0
- data/test/br_nfe/servico/betha/v1/cancelamento_nfs_test.rb +62 -0
- data/test/br_nfe/servico/betha/v1/consulta_lote_rps_test.rb +42 -0
- data/test/br_nfe/servico/betha/v1/consulta_nfs_por_rps_test.rb +68 -0
- data/test/br_nfe/servico/betha/v1/consulta_nfse_test.rb +57 -0
- data/test/br_nfe/servico/betha/v1/consulta_situacao_lote_rps_test.rb +27 -0
- data/test/br_nfe/servico/betha/v1/gateway_test.rb +174 -0
- data/test/br_nfe/servico/betha/v1/recepcao_lote_rps_test.rb +235 -0
- data/test/br_nfe/servico/response/default_test.rb +54 -0
- data/test/br_nfe/servico/response/nota_fiscal_test.rb +41 -0
- data/test/br_nfe/servico/rps_test.rb +214 -0
- data/test/certificado.rb +12 -0
- data/test/factories/base.rb +5 -0
- data/test/factories/condicao_pagamento.rb +10 -0
- data/test/factories/destinatario.rb +11 -0
- data/test/factories/emitente.rb +15 -0
- data/test/factories/endereco.rb +12 -0
- data/test/factories/servico/base.rb +5 -0
- data/test/factories/servico/betha/base.rb +5 -0
- data/test/factories/servico/betha/v1/build_response.rb +6 -0
- data/test/factories/servico/betha/v1/cancelamento_nfs.rb +7 -0
- data/test/factories/servico/betha/v1/consulta_lote_rps.rb +6 -0
- data/test/factories/servico/betha/v1/consulta_nfs_por_rps.rb +6 -0
- data/test/factories/servico/betha/v1/consulta_nfse.rb +8 -0
- data/test/factories/servico/betha/v1/consulta_situacao_lote_rps.rb +6 -0
- data/test/factories/servico/betha/v1/gateway.rb +5 -0
- data/test/factories/servico/betha/v1/recepcao_lote_rps.rb +6 -0
- data/test/factories/servico/intermediario.rb +7 -0
- data/test/factories/servico/response/default.rb +10 -0
- data/test/factories/servico/response/nota_fiscal.rb +47 -0
- data/test/factories/servico/rps.rb +44 -0
- data/test/test_helper.rb +39 -0
- metadata +263 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: f5bff6e1698aa7f99b9173ab613f2b9de121b63e
|
|
4
|
+
data.tar.gz: 204e49ce93ce25e694a3b6a097ba6160bdf0f65e
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 06922cf1c5b2512e79f14b70a3c97410a84e683cb2ee88bc7184ffc246c84546e4ea4038396a417ff8e4dc2b45a64727905102f2273be85260cce467a3b999a7
|
|
7
|
+
data.tar.gz: c9d88601560d5130d7d8c4d04e4226d68a050f8a98f96d7a74605a8f06e1c04609f3993805cd244274bdc14e8c6c380f5266429ae811e2154da962464556087e
|
data/Gemfile
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
source 'http://rubygems.org'
|
|
2
|
+
|
|
3
|
+
gemspec
|
|
4
|
+
|
|
5
|
+
group :test do
|
|
6
|
+
# gem "mocha", :require => false
|
|
7
|
+
gem "mocha", :require => false
|
|
8
|
+
gem "factory_girl_rails"
|
|
9
|
+
gem 'minitest-reporters'
|
|
10
|
+
gem 'minitest-rails'
|
|
11
|
+
gem 'minitest-spec-rails'
|
|
12
|
+
gem 'shoulda-matchers', require: false
|
|
13
|
+
gem "minitest-matchers_vaccine"
|
|
14
|
+
gem 'simplecov'
|
|
15
|
+
end
|
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
br_nfe (1.0.0)
|
|
5
|
+
activemodel (~> 4.2)
|
|
6
|
+
activesupport (~> 4.2)
|
|
7
|
+
nokogiri (~> 1.6)
|
|
8
|
+
rake (>= 0.8.7)
|
|
9
|
+
savon (~> 2.11)
|
|
10
|
+
signer
|
|
11
|
+
|
|
12
|
+
GEM
|
|
13
|
+
remote: http://rubygems.org/
|
|
14
|
+
specs:
|
|
15
|
+
actionmailer (4.2.3)
|
|
16
|
+
actionpack (= 4.2.3)
|
|
17
|
+
actionview (= 4.2.3)
|
|
18
|
+
activejob (= 4.2.3)
|
|
19
|
+
mail (~> 2.5, >= 2.5.4)
|
|
20
|
+
rails-dom-testing (~> 1.0, >= 1.0.5)
|
|
21
|
+
actionpack (4.2.3)
|
|
22
|
+
actionview (= 4.2.3)
|
|
23
|
+
activesupport (= 4.2.3)
|
|
24
|
+
rack (~> 1.6)
|
|
25
|
+
rack-test (~> 0.6.2)
|
|
26
|
+
rails-dom-testing (~> 1.0, >= 1.0.5)
|
|
27
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
|
28
|
+
actionview (4.2.3)
|
|
29
|
+
activesupport (= 4.2.3)
|
|
30
|
+
builder (~> 3.1)
|
|
31
|
+
erubis (~> 2.7.0)
|
|
32
|
+
rails-dom-testing (~> 1.0, >= 1.0.5)
|
|
33
|
+
rails-html-sanitizer (~> 1.0, >= 1.0.2)
|
|
34
|
+
activejob (4.2.3)
|
|
35
|
+
activesupport (= 4.2.3)
|
|
36
|
+
globalid (>= 0.3.0)
|
|
37
|
+
activemodel (4.2.3)
|
|
38
|
+
activesupport (= 4.2.3)
|
|
39
|
+
builder (~> 3.1)
|
|
40
|
+
activerecord (4.2.3)
|
|
41
|
+
activemodel (= 4.2.3)
|
|
42
|
+
activesupport (= 4.2.3)
|
|
43
|
+
arel (~> 6.0)
|
|
44
|
+
activesupport (4.2.3)
|
|
45
|
+
i18n (~> 0.7)
|
|
46
|
+
json (~> 1.7, >= 1.7.7)
|
|
47
|
+
minitest (~> 5.1)
|
|
48
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
|
49
|
+
tzinfo (~> 1.1)
|
|
50
|
+
akami (1.3.1)
|
|
51
|
+
gyoku (>= 0.4.0)
|
|
52
|
+
nokogiri
|
|
53
|
+
ansi (1.5.0)
|
|
54
|
+
arel (6.0.2)
|
|
55
|
+
builder (3.2.2)
|
|
56
|
+
docile (1.1.5)
|
|
57
|
+
erubis (2.7.0)
|
|
58
|
+
factory_girl (4.5.0)
|
|
59
|
+
activesupport (>= 3.0.0)
|
|
60
|
+
factory_girl_rails (4.5.0)
|
|
61
|
+
factory_girl (~> 4.5.0)
|
|
62
|
+
railties (>= 3.0.0)
|
|
63
|
+
globalid (0.3.5)
|
|
64
|
+
activesupport (>= 4.1.0)
|
|
65
|
+
gyoku (1.3.1)
|
|
66
|
+
builder (>= 2.1.2)
|
|
67
|
+
httpi (2.4.1)
|
|
68
|
+
rack
|
|
69
|
+
i18n (0.7.0)
|
|
70
|
+
json (1.8.3)
|
|
71
|
+
loofah (2.0.2)
|
|
72
|
+
nokogiri (>= 1.5.9)
|
|
73
|
+
mail (2.6.3)
|
|
74
|
+
mime-types (>= 1.16, < 3)
|
|
75
|
+
metaclass (0.0.4)
|
|
76
|
+
mime-types (2.6.1)
|
|
77
|
+
mini_portile (0.6.2)
|
|
78
|
+
minitest (5.7.0)
|
|
79
|
+
minitest-matchers_vaccine (1.0.3)
|
|
80
|
+
minitest (~> 5.0)
|
|
81
|
+
minitest-rails (2.2.0)
|
|
82
|
+
minitest (~> 5.7)
|
|
83
|
+
railties (~> 4.1)
|
|
84
|
+
minitest-reporters (1.0.19)
|
|
85
|
+
ansi
|
|
86
|
+
builder
|
|
87
|
+
minitest (>= 5.0)
|
|
88
|
+
ruby-progressbar
|
|
89
|
+
minitest-spec-rails (5.2.2)
|
|
90
|
+
minitest (~> 5.0)
|
|
91
|
+
rails (~> 4.1)
|
|
92
|
+
mocha (1.1.0)
|
|
93
|
+
metaclass (~> 0.0.1)
|
|
94
|
+
nokogiri (1.6.6.2)
|
|
95
|
+
mini_portile (~> 0.6.0)
|
|
96
|
+
nori (2.6.0)
|
|
97
|
+
rack (1.6.4)
|
|
98
|
+
rack-test (0.6.3)
|
|
99
|
+
rack (>= 1.0)
|
|
100
|
+
rails (4.2.3)
|
|
101
|
+
actionmailer (= 4.2.3)
|
|
102
|
+
actionpack (= 4.2.3)
|
|
103
|
+
actionview (= 4.2.3)
|
|
104
|
+
activejob (= 4.2.3)
|
|
105
|
+
activemodel (= 4.2.3)
|
|
106
|
+
activerecord (= 4.2.3)
|
|
107
|
+
activesupport (= 4.2.3)
|
|
108
|
+
bundler (>= 1.3.0, < 2.0)
|
|
109
|
+
railties (= 4.2.3)
|
|
110
|
+
sprockets-rails
|
|
111
|
+
rails-deprecated_sanitizer (1.0.3)
|
|
112
|
+
activesupport (>= 4.2.0.alpha)
|
|
113
|
+
rails-dom-testing (1.0.6)
|
|
114
|
+
activesupport (>= 4.2.0.beta, < 5.0)
|
|
115
|
+
nokogiri (~> 1.6.0)
|
|
116
|
+
rails-deprecated_sanitizer (>= 1.0.1)
|
|
117
|
+
rails-html-sanitizer (1.0.2)
|
|
118
|
+
loofah (~> 2.0)
|
|
119
|
+
railties (4.2.3)
|
|
120
|
+
actionpack (= 4.2.3)
|
|
121
|
+
activesupport (= 4.2.3)
|
|
122
|
+
rake (>= 0.8.7)
|
|
123
|
+
thor (>= 0.18.1, < 2.0)
|
|
124
|
+
rake (10.4.2)
|
|
125
|
+
ruby-progressbar (1.7.5)
|
|
126
|
+
savon (2.11.1)
|
|
127
|
+
akami (~> 1.2)
|
|
128
|
+
builder (>= 2.1.2)
|
|
129
|
+
gyoku (~> 1.2)
|
|
130
|
+
httpi (~> 2.3)
|
|
131
|
+
nokogiri (>= 1.4.0)
|
|
132
|
+
nori (~> 2.4)
|
|
133
|
+
wasabi (~> 3.4)
|
|
134
|
+
shoulda-matchers (2.8.0)
|
|
135
|
+
activesupport (>= 3.0.0)
|
|
136
|
+
signer (1.4.2)
|
|
137
|
+
nokogiri (>= 1.5.1)
|
|
138
|
+
simplecov (0.10.0)
|
|
139
|
+
docile (~> 1.1.0)
|
|
140
|
+
json (~> 1.8)
|
|
141
|
+
simplecov-html (~> 0.10.0)
|
|
142
|
+
simplecov-html (0.10.0)
|
|
143
|
+
sprockets (3.2.0)
|
|
144
|
+
rack (~> 1.0)
|
|
145
|
+
sprockets-rails (2.3.2)
|
|
146
|
+
actionpack (>= 3.0)
|
|
147
|
+
activesupport (>= 3.0)
|
|
148
|
+
sprockets (>= 2.8, < 4.0)
|
|
149
|
+
thor (0.19.1)
|
|
150
|
+
thread_safe (0.3.5)
|
|
151
|
+
tzinfo (1.2.2)
|
|
152
|
+
thread_safe (~> 0.1)
|
|
153
|
+
wasabi (3.5.0)
|
|
154
|
+
httpi (~> 2.0)
|
|
155
|
+
nokogiri (>= 1.4.2)
|
|
156
|
+
|
|
157
|
+
PLATFORMS
|
|
158
|
+
ruby
|
|
159
|
+
|
|
160
|
+
DEPENDENCIES
|
|
161
|
+
br_nfe!
|
|
162
|
+
factory_girl_rails
|
|
163
|
+
minitest-matchers_vaccine
|
|
164
|
+
minitest-rails
|
|
165
|
+
minitest-reporters
|
|
166
|
+
minitest-spec-rails
|
|
167
|
+
mocha
|
|
168
|
+
shoulda-matchers
|
|
169
|
+
simplecov
|
data/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2015 Bruno M. Mergen
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.markdown
ADDED
data/Rakefile
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'rake/testtask'
|
|
2
|
+
|
|
3
|
+
Rake::TestTask.new do |task|
|
|
4
|
+
task.libs << %w(test lib)
|
|
5
|
+
task.pattern = 'test/**/*_test.rb'
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
desc "Open an irb session preloaded with this library"
|
|
9
|
+
task :console do
|
|
10
|
+
sh "irb -rubygems -I lib -r br_nfe.rb"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
task :default => :test
|
data/br_nfe.gemspec
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
require File.expand_path('../lib/br_nfe/version', __FILE__)
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |gem|
|
|
5
|
+
gem.authors = ["Bruno M. Mergen"]
|
|
6
|
+
gem.email = ["brunomergen@gmail.com"]
|
|
7
|
+
gem.description = %q{Emissão de Notas Fiscais Eletrônicas em Ruby}
|
|
8
|
+
gem.summary = %q{Emissão de Notas Fiscais Eletrônicas em Ruby}
|
|
9
|
+
gem.homepage = "https://github.com/Brunomm/br_nfe"
|
|
10
|
+
gem.license = "BSD"
|
|
11
|
+
|
|
12
|
+
gem.files = `git ls-files`.split($\).reject { |f| ['.pdf','.xls'].include?(File.extname(f)) }
|
|
13
|
+
gem.test_files = `git ls-files -- test/**/*`.split("\n")
|
|
14
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
|
15
|
+
gem.name = "br_nfe"
|
|
16
|
+
gem.require_paths = ["lib"]
|
|
17
|
+
gem.version = BrNfe::Version::CURRENT
|
|
18
|
+
|
|
19
|
+
gem.required_ruby_version = '>= 2.1'
|
|
20
|
+
|
|
21
|
+
gem.add_dependency "rake", '>= 0.8.7'
|
|
22
|
+
gem.add_dependency "activesupport", '~> 4.2'
|
|
23
|
+
gem.add_dependency "activemodel", '~> 4.2'
|
|
24
|
+
gem.add_dependency "nokogiri", "~> 1.6"
|
|
25
|
+
gem.add_dependency "savon", "~> 2.11"
|
|
26
|
+
gem.add_dependency "signer"
|
|
27
|
+
|
|
28
|
+
end
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
module BrNfe
|
|
2
|
+
class ActiveModelBase
|
|
3
|
+
include ActiveModel::Model
|
|
4
|
+
|
|
5
|
+
def initialize(attributes = {})
|
|
6
|
+
attributes = default_values.merge!(attributes)
|
|
7
|
+
assign_attributes(attributes)
|
|
8
|
+
yield self if block_given?
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def assign_attributes(attributes)
|
|
12
|
+
attributes ||= {}
|
|
13
|
+
attributes.each do |name, value|
|
|
14
|
+
send("#{name}=", value)
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def default_values
|
|
19
|
+
{}
|
|
20
|
+
end
|
|
21
|
+
protected
|
|
22
|
+
|
|
23
|
+
##################### FORMATAÇÃO DE VALORES #####################
|
|
24
|
+
# Dependendo do WebService de emissão de nota, é necssário passar alguns valores
|
|
25
|
+
# em formatos diferentes.
|
|
26
|
+
# Os metodos a seguir neste bloco poderão ser sobrescritos para cada Webservice
|
|
27
|
+
# tendo assim, um padrão definido para montar os dados para envio.
|
|
28
|
+
#
|
|
29
|
+
def value_date(value)
|
|
30
|
+
value = Date.parse(value.to_s)
|
|
31
|
+
value.to_s(:br_nfe)
|
|
32
|
+
rescue
|
|
33
|
+
return ''
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def value_date_time(data)
|
|
37
|
+
data_hora = DateTime.parse(data.to_s)
|
|
38
|
+
data_hora.to_s(:br_nfe)
|
|
39
|
+
rescue
|
|
40
|
+
return ''
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# Irá retornar 1(true) e 2(false)
|
|
44
|
+
def value_true_false(value)
|
|
45
|
+
BrNfe.true_values.include?(value) ? '1' : '2'
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
# Deve receber um valor do tipo float
|
|
49
|
+
# Irá retornar o valor com a precisão
|
|
50
|
+
# Alguns WS convertem os valores para String com separador de milhar uma vírgula
|
|
51
|
+
#
|
|
52
|
+
def value_monetary(value, precision=2)
|
|
53
|
+
return unless value
|
|
54
|
+
value.to_f.round(2)
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def value_amount(value, precision=2)
|
|
58
|
+
value_monetary(value, precision)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
end
|
|
62
|
+
end
|
data/lib/br_nfe/base.rb
ADDED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
module BrNfe
|
|
2
|
+
class Base < BrNfe::ActiveModelBase
|
|
3
|
+
|
|
4
|
+
include BrNfe::Helper::HaveEmitente
|
|
5
|
+
|
|
6
|
+
attr_accessor :certificado_password
|
|
7
|
+
attr_accessor :certificado_path
|
|
8
|
+
attr_accessor :certificado_value
|
|
9
|
+
|
|
10
|
+
validate :validar_emitente
|
|
11
|
+
validates :certificado, presence: true, if: :certificado_obrigatorio?
|
|
12
|
+
|
|
13
|
+
# Método que deve ser sobrescrito para as ações que necessitam do certificado para assinatura
|
|
14
|
+
def certificado_obrigatorio?
|
|
15
|
+
false
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Caso não tenha o certificado salvo em arquivo, pode setar a string do certificado direto pelo atributo certificado_value
|
|
19
|
+
# Caso tenha o certificado em arquivo, basta setar o atributo certificado_path e deixar o atributo certificado_value em branco
|
|
20
|
+
def certificado_value
|
|
21
|
+
@certificado_value ||= File.read(certificado_path)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
attr_accessor :env
|
|
25
|
+
|
|
26
|
+
def env
|
|
27
|
+
@env ||= :production
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def response
|
|
31
|
+
@response
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def wsdl
|
|
35
|
+
raise "Não implementado."
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def env_namespace
|
|
39
|
+
:soapenv
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def method_wsdl
|
|
43
|
+
raise "Não implementado."
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def xml_builder
|
|
47
|
+
raise "Não implementado."
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def namespace_identifier
|
|
51
|
+
raise 'Não implementado.'
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def namespaces
|
|
55
|
+
{}
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def certificado
|
|
59
|
+
@certificado ||= OpenSSL::PKCS12.new(certificado_value, certificado_password)
|
|
60
|
+
rescue
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def certificado=(value)
|
|
64
|
+
@certificado = value
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def wsdl_encoding
|
|
68
|
+
"UTF-8"
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def client_wsdl
|
|
72
|
+
@client_wsdl ||= Savon.client({
|
|
73
|
+
namespaces: namespaces,
|
|
74
|
+
env_namespace: env_namespace,
|
|
75
|
+
wsdl: wsdl,
|
|
76
|
+
namespace_identifier: namespace_identifier,
|
|
77
|
+
encoding: wsdl_encoding,
|
|
78
|
+
log: BrNfe.client_wsdl_log,
|
|
79
|
+
pretty_print_xml: BrNfe.client_wsdl_pretty_print_xml,
|
|
80
|
+
ssl_verify_mode: BrNfe.client_wsdl_ssl_verify_mode,
|
|
81
|
+
ssl_cert_file: BrNfe.client_wsdl_ssl_cert_file,
|
|
82
|
+
ssl_cert_key_file: BrNfe.client_wsdl_ssl_cert_key_file,
|
|
83
|
+
ssl_cert_key_password: BrNfe.client_wsdl_ssl_cert_key_password
|
|
84
|
+
})
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
private
|
|
88
|
+
|
|
89
|
+
def tag_cpf_cnpj(xml, cpf_cnpj)
|
|
90
|
+
cpf_cnpj = BrNfe::Helper::CpfCnpj.new(cpf_cnpj)
|
|
91
|
+
if cpf_cnpj.cnpj?
|
|
92
|
+
xml.Cnpj cpf_cnpj.sem_formatacao
|
|
93
|
+
elsif cpf_cnpj.cpf?
|
|
94
|
+
xml.Cpf cpf_cnpj.sem_formatacao
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def assinatura_xml(data_xml, uri='')
|
|
100
|
+
data_xml = format_data_xml_for_signature(data_xml)
|
|
101
|
+
ass = Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
|
|
102
|
+
xml.Signature(xmlns: 'http://www.w3.org/2000/09/xmldsig#') do |signature|
|
|
103
|
+
|
|
104
|
+
info = canonicalize(signed_info(data_xml, uri).doc.root())
|
|
105
|
+
signature.__send__ :insert, Nokogiri::XML::DocumentFragment.parse( info.to_s )
|
|
106
|
+
|
|
107
|
+
signature.SignatureValue xml_signature_value(info)
|
|
108
|
+
|
|
109
|
+
signature.KeyInfo {
|
|
110
|
+
signature.X509Data {
|
|
111
|
+
signature.X509Certificate certificado.certificate.to_s.gsub(/\-\-\-\-\-[A-Z]+ CERTIFICATE\-\-\-\-\-/, "").gsub(/\n/,"")
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
end
|
|
115
|
+
end.doc.root
|
|
116
|
+
canonicalize ass
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def signed_info(data_xml, uri='')
|
|
120
|
+
Nokogiri::XML::Builder.new(encoding: 'UTF-8') do |xml|
|
|
121
|
+
xml.SignedInfo(xmlns: "http://www.w3.org/2000/09/xmldsig#") do |info|
|
|
122
|
+
info.CanonicalizationMethod(Algorithm: 'http://www.w3.org/2001/10/xml-exc-c14n#')
|
|
123
|
+
info.SignatureMethod(Algorithm: 'http://www.w3.org/2000/09/xmldsig#rsa-sha1')
|
|
124
|
+
info.Reference('URI' => uri){
|
|
125
|
+
info.Transforms{
|
|
126
|
+
info.Transform(:Algorithm => 'http://www.w3.org/2000/09/xmldsig#enveloped-signature')
|
|
127
|
+
info.Transform(:Algorithm => 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315')
|
|
128
|
+
}
|
|
129
|
+
info.DigestMethod(:Algorithm => 'http://www.w3.org/2000/09/xmldsig#sha1')
|
|
130
|
+
info.DigestValue xml_digest_value(data_xml)
|
|
131
|
+
}
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
def xml_signature_value(xml)
|
|
137
|
+
sign_canon = canonicalize(xml)
|
|
138
|
+
signature_hash = certificado.key.sign(OpenSSL::Digest::SHA1.new, sign_canon)
|
|
139
|
+
remove_quebras Base64.encode64( signature_hash )
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
def xml_digest_value(xml)
|
|
143
|
+
xml_canon = canonicalize(xml)
|
|
144
|
+
remove_quebras Base64.encode64(OpenSSL::Digest::SHA1.digest(xml_canon))
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
def canonicalize(xml)
|
|
149
|
+
xml = Nokogiri::XML(xml.to_s, &:noblanks)
|
|
150
|
+
xml.canonicalize(Nokogiri::XML::XML_C14N_EXCLUSIVE_1_0)
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def remove_quebras(str)
|
|
154
|
+
str.gsub(/\n/,'').gsub(/\t/,'').strip
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def format_data_xml_for_signature(data_xml)
|
|
158
|
+
data_xml
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def validar_emitente
|
|
162
|
+
if emitente.invalid?
|
|
163
|
+
emitente.errors.full_messages.map{|msg| errors.add(:emitente, msg) }
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
end
|
|
168
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module BrNfe
|
|
2
|
+
class CondicaoPagamento < BrNfe::ActiveModelBase
|
|
3
|
+
|
|
4
|
+
def initialize(attributes = {})
|
|
5
|
+
@parcelas = [] # Para poder utilizar o << para adicionar parcelas
|
|
6
|
+
super
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def default_values
|
|
10
|
+
{condicao: 'A_VISTA'}
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# A_VISTA ou A_PRAZO
|
|
14
|
+
attr_accessor :condicao
|
|
15
|
+
|
|
16
|
+
#
|
|
17
|
+
# EX Valor para parcelas = [{valor: 50.33, vencimento: '15/11/2016'}, {valor: '27.00', vencimento: '2016-11-15'}]
|
|
18
|
+
#
|
|
19
|
+
attr_accessor :parcelas
|
|
20
|
+
|
|
21
|
+
def parcelas
|
|
22
|
+
@parcelas = [@parcelas].flatten
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
module BrNfe
|
|
2
|
+
class Destinatario < BrNfe::ActiveModelBase
|
|
3
|
+
include BrNfe::Helper::HaveAddress
|
|
4
|
+
|
|
5
|
+
attr_accessor :cpf_cnpj
|
|
6
|
+
attr_accessor :inscricao_municipal
|
|
7
|
+
attr_accessor :inscricao_estadual
|
|
8
|
+
attr_accessor :inscricao_suframa
|
|
9
|
+
attr_accessor :razao_social
|
|
10
|
+
attr_accessor :nome_fantasia
|
|
11
|
+
attr_accessor :telefone
|
|
12
|
+
attr_accessor :email
|
|
13
|
+
|
|
14
|
+
validates :cpf_cnpj, :razao_social, presence: true
|
|
15
|
+
validate :validar_endereco
|
|
16
|
+
|
|
17
|
+
def razao_social
|
|
18
|
+
"#{@razao_social}".to_valid_format_nf
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def nome_fantasia
|
|
22
|
+
"#{@nome_fantasia}".to_valid_format_nf
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
module BrNfe
|
|
2
|
+
class Emitente < BrNfe::ActiveModelBase
|
|
3
|
+
include BrNfe::Helper::HaveAddress
|
|
4
|
+
|
|
5
|
+
# Obrigatórios
|
|
6
|
+
attr_accessor :cnpj
|
|
7
|
+
attr_accessor :inscricao_municipal
|
|
8
|
+
attr_accessor :razao_social
|
|
9
|
+
attr_accessor :natureza_operacao
|
|
10
|
+
|
|
11
|
+
#Não obrigatórios
|
|
12
|
+
attr_accessor :nome_fantasia
|
|
13
|
+
attr_accessor :telefone
|
|
14
|
+
attr_accessor :email
|
|
15
|
+
attr_accessor :regime_especial_tributacao
|
|
16
|
+
attr_accessor :optante_simples_nacional
|
|
17
|
+
attr_accessor :incentivo_fiscal
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
validates :inscricao_municipal, :natureza_operacao, :cnpj, :razao_social, presence: true
|
|
21
|
+
validate :validar_endereco
|
|
22
|
+
|
|
23
|
+
def razao_social
|
|
24
|
+
"#{@razao_social}".to_valid_format_nf
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def nome_fantasia
|
|
28
|
+
"#{@nome_fantasia}".to_valid_format_nf
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def optante_simples_nacional?
|
|
32
|
+
BrNfe.true_values.include?(optante_simples_nacional)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def incentivo_fiscal?
|
|
36
|
+
BrNfe.true_values.include?(incentivo_fiscal)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module BrNfe
|
|
2
|
+
class Endereco < BrNfe::ActiveModelBase
|
|
3
|
+
|
|
4
|
+
def default_values
|
|
5
|
+
{
|
|
6
|
+
codigo_pais: '1058',
|
|
7
|
+
nome_pais: 'BRASIL'
|
|
8
|
+
}
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
attr_accessor :logradouro
|
|
12
|
+
attr_accessor :numero
|
|
13
|
+
attr_accessor :complemento
|
|
14
|
+
attr_accessor :bairro
|
|
15
|
+
attr_accessor :nome_municipio
|
|
16
|
+
attr_accessor :codigo_municipio
|
|
17
|
+
attr_accessor :uf
|
|
18
|
+
attr_accessor :cep
|
|
19
|
+
attr_accessor :codigo_pais # defaul: 1058 (Brasil)
|
|
20
|
+
attr_accessor :nome_pais # defaul: BRASIL
|
|
21
|
+
|
|
22
|
+
validates :logradouro, :numero, :bairro, :codigo_municipio, :uf, :cep, presence: true
|
|
23
|
+
|
|
24
|
+
def logradouro
|
|
25
|
+
"#{@logradouro}".to_valid_format_nf
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def complemento
|
|
29
|
+
"#{@complemento}".to_valid_format_nf
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def bairro
|
|
33
|
+
"#{@bairro}".to_valid_format_nf
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def nome_municipio
|
|
37
|
+
"#{@nome_municipio}".to_valid_format_nf
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def nome_pais
|
|
41
|
+
"#{@nome_pais}".to_valid_format_nf
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
module BrNfe
|
|
2
|
+
module Helper
|
|
3
|
+
class CpfCnpj
|
|
4
|
+
|
|
5
|
+
def initialize(cpf_cnpj)
|
|
6
|
+
@cpf_cnpj = ajusta_cpf_cnpj_com_zero("#{cpf_cnpj}")
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def cpf?
|
|
10
|
+
cpf_ou_cnpj? == :cpf
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def cnpj?
|
|
14
|
+
cpf_ou_cnpj? == :cnpj
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def cpf_ou_cnpj?
|
|
18
|
+
sem_formatacao.size > 11 ? :cnpj : :cpf
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def tipo_documento(tamanho = 2)
|
|
22
|
+
return '0' if sem_formatacao.blank?
|
|
23
|
+
sem_formatacao.size < 14 ? '1'.rjust(tamanho, '0') : '2'.rjust(tamanho, '0')
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def sem_formatacao
|
|
27
|
+
@cpf_cnpj.gsub(/[\.]|[\-]|[\/]/,'')
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def com_formatacao
|
|
31
|
+
cnpj? ? formata_cnpj : formata_cpf
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def formatado_com_label
|
|
35
|
+
cnpj? ? "CNPJ #{formata_cnpj}" : "CPF #{formata_cpf}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
def ajusta_cpf_cnpj_com_zero(value)
|
|
41
|
+
return "" if value.blank?
|
|
42
|
+
if value.to_s.size <= 11
|
|
43
|
+
value.to_s.rjust(11, '0')
|
|
44
|
+
else
|
|
45
|
+
value.to_s.rjust(14, '0')
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def formata_cpf
|
|
50
|
+
@cpf_cnpj.gsub!(/[\.]|[\-]|[\/]/,'')
|
|
51
|
+
"#{@cpf_cnpj[0..2]}.#{@cpf_cnpj[3..5]}.#{@cpf_cnpj[6..8]}-#{@cpf_cnpj[9..10]}"
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def formata_cnpj
|
|
55
|
+
@cpf_cnpj.gsub!(/[\.]|[\-]|[\/]/,'')
|
|
56
|
+
"#{@cpf_cnpj[0..1]}.#{@cpf_cnpj[2..4]}.#{@cpf_cnpj[5..7]}/#{@cpf_cnpj[8..11]}-#{@cpf_cnpj[12..13]}"
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|