nfse-carioca 0.0.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 59ed7774a62b9a4a6c1b266f9226c4cb4db1f6be
4
+ data.tar.gz: 5b882e9110d20068c1d10e8520c1f03bff1f2c01
5
+ SHA512:
6
+ metadata.gz: b1212ac5ff1c62b666840cda48d8a97da9ada307f9284705b7f8b15afd6e4beec735dd0dbf37d66bbb4ba719ca283f4e99f8b56915cf11f555e08a5e3671c03e
7
+ data.tar.gz: 2701cdf0f3daf9806b7b2a325031b16ad6492b6d56fc5c78503a2375a3710a25c74c0512a1b408a6c1f54c48fafaae17ce8e9abd9bccc6d2134077cca476da7a
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
15
+ .vagrant
16
+ *.pem
17
+ *.pfx
18
+
19
+ .ruby-version
20
+ .ruby-gemset
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --require spec_helper
data/CHANGELOG.md ADDED
@@ -0,0 +1,7 @@
1
+ ## 0.0.1 (Unreleased)
2
+
3
+ ### features
4
+
5
+ ### improvements
6
+
7
+ ### bug fixes
data/CONTRIBUTING.md ADDED
@@ -0,0 +1,35 @@
1
+ # Contributing
2
+
3
+ We love pull requests. Here's a quick guide:
4
+
5
+ 1. Fork the repo.
6
+
7
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
8
+
9
+ 3. Run the tests. We only take pull requests with passing tests, and it's great
10
+ to know that you have a clean slate: `bundle && rake`
11
+
12
+ 4. Add a test for your change. Only refactoring and documentation changes
13
+ require no new tests. If you are adding functionality or fixing a bug, we need
14
+ a test!
15
+
16
+ 5. Make the test pass.
17
+
18
+ 6. Update [CHANGELOG.md][changelog] with a brief description of your changes under the `unreleased` heading.
19
+
20
+ 7. Commit your changes (`git commit -am 'Added some feature'`)
21
+
22
+ 8. Push to the branch (`git push origin my-new-feature`)
23
+
24
+ 9. Create new Pull Request
25
+
26
+ At this point you're waiting on us. We like to at least give you feedback, if not just
27
+ accept it, within a few days, depending on our internal priorities.
28
+
29
+ Some things that will increase the chance that your pull request is accepted is to follow the practices described on [Ruby style guide][rubysg], [Rails style guide][railssg] and [Better Specs][bs].
30
+
31
+
32
+ [changelog]: https://github.com/luzvc/nfse-carioca/blob/master/CHANGELOG.md
33
+ [rubysg]: https://github.com/bbatsov/ruby-style-guide
34
+ [railssg]: https://github.com/bbatsov/rails-style-guide
35
+ [bs]: http://betterspecs.org/
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # NFSeCarioca
2
+
3
+ NFSeCarioca Carioca é uma gem que visa facilitar a comunicação com a API do [notacarioca][nc], através de um cliente ruby.
4
+
5
+ :warning: Essa lib ainda está em desenvolvimento. :warning:
6
+
7
+ ## Instalação
8
+
9
+ Adicione esta linha ao seu ao Gemfile da sua aplicação:
10
+
11
+ :warning: **A gem ainda não foi publicada, para instalar use.** :warning:
12
+
13
+ ```ruby
14
+ gem 'nfse-carioca', github: "luzvc/nfse-carioca"
15
+ ```
16
+
17
+ Rode o bundle:
18
+
19
+ $ bundle
20
+
21
+
22
+ ## Como usar?
23
+
24
+ ### Configurando os certificados
25
+
26
+ Crie um arquivo `config/initializers/nfse_carioca.rb` e adicione:
27
+
28
+ ```ruby
29
+ NFSeCarioca.configure do |config|
30
+ config.test_mode = true # Defines to use on test mode.
31
+
32
+ config.cert_pem_path = "/your/string/path/to/certicate.pem"
33
+ config.ca_cert_pem_path = "/your/string/path/to/ca/certicate.pem"
34
+ config.cert_key_pem_path = "/your/string/path/to/certicate/key.pem"
35
+ config.ssl_cert_key_password = "very-secure-encrypted-password"
36
+ end
37
+ ```
38
+
39
+ ### Criando uma NFSeCarioca
40
+
41
+ ```ruby
42
+ # valores a serem usados na NFSeCarioca a ser gerada
43
+ infos = {
44
+ identification_number: "01",
45
+ description: "Venda do Serviço XYZ.",
46
+ provider: {
47
+ cnpj: "11199990000111",
48
+ inscricao_municipal: "04807995"
49
+ },
50
+ customer: {
51
+ kind: "Cnpj",
52
+ code: "22220099000111",
53
+ full_name: "XPTO Tecnologia Ltda.",
54
+ phone_number: "2222-2222", #opcional
55
+ email: "customer@example.com", #opcional
56
+ address: {
57
+ street: "Rua qualquer nome",
58
+ number: "33",
59
+ complement: "Sala 1",
60
+ neighborhood: "Seu bairro",
61
+ city_ibge_code: "3550308",
62
+ state_code: "SP",
63
+ zipcode: "22255777"
64
+ }
65
+ }
66
+ }
67
+
68
+ invoice = Invoice.new(infos)
69
+
70
+ gerador = NFSeCarioca::GerarNFSe.new(invoice)
71
+
72
+ # Conecta na API do Nota Carioca para gerar a NFSeCarioca
73
+ response = gerador.execute!
74
+ ```
75
+
76
+ ## Versões
77
+
78
+ NFSeCarioca segue o versionamento semântico([Semantic Versioning][sv]).
79
+
80
+ ## Issues
81
+
82
+ Se você encontrar um bug, por favor crie um [Github Issue][issues].
83
+
84
+ ## Contributing
85
+
86
+ Para maiores detalhes veja [CONTRIBUTING.md][contrib].
87
+
88
+ [nc]: http://notacarioca.rio.gov.br
89
+ [sv]: http://semver.org/lang/pt-BR/
90
+ [issues]: https://github.com/luzvc/nfse-carioca/issues
91
+ [contrib]: https://github.com/luzvc/nfse-carioca/blob/master/CONTRIBUTING.md
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ begin
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task :default => :spec
9
+ rescue LoadError
10
+ # no rspec available
11
+ end
@@ -0,0 +1,28 @@
1
+ require "ostruct"
2
+ require "virtus"
3
+ require 'active_support/core_ext/hash'
4
+ require "nfse_carioca/version"
5
+ require "nfse_carioca/configuration"
6
+ require "nfse_carioca/nota_carioca_client"
7
+ require "nfse_carioca/models/invoice"
8
+ require "nfse_carioca/gerar_nfse"
9
+ require "nfse_carioca/cancelar_nfse"
10
+
11
+ module NFSeCarioca
12
+
13
+ def self.configure(&block)
14
+ yield configuration
15
+ end
16
+
17
+ def self.configuration
18
+ @configuration ||= NFSeCarioca::Configuration.instance
19
+ end
20
+
21
+ def self.method_missing(method, *args)
22
+ configuration.send("#{method}")
23
+ end
24
+
25
+ def self.reset
26
+ @configuration = nil
27
+ end
28
+ end
@@ -0,0 +1,36 @@
1
+ require "nfse_carioca/nota_carioca_response"
2
+ require "nfse_carioca/cancelar_nfse_xml"
3
+
4
+ module NFSeCarioca
5
+ class CancelarNFSe < NotaCariocaClient
6
+
7
+ def initialize(params={})
8
+ @params = params
9
+ end
10
+
11
+ def execute!
12
+ Response.new(call(:cancelar_nfse, nfse_xml))
13
+ end
14
+
15
+ private
16
+
17
+ def nfse_xml
18
+ CancelarNFSeXML.new(@params).to_xml
19
+ end
20
+
21
+ class Response < NotaCariocaResponse
22
+ def output_xml
23
+ @output_xml ||= @response.hash[:envelope][:body][:cancelar_nfse_response][:output_xml]
24
+ end
25
+
26
+ def success?
27
+ nota_carioca_xml["CancelarNfseResposta"]["Cancelamento"]["Confirmacao"].present? rescue false
28
+ end
29
+
30
+ def error_message
31
+ nota_carioca_xml["CancelarNfseResposta"]["ListaMensagemRetorno"]["MensagemRetorno"]["Correcao"] unless success?
32
+ end
33
+
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,31 @@
1
+ module NFSeCarioca
2
+ class CancelarNFSeXML
3
+ include Virtus.model
4
+
5
+ SERVICO_CODIGO_MUNICIPIO = {
6
+ RIO_DE_JANEIRO: "3304557"
7
+ }
8
+
9
+ attribute :nf_number, String
10
+ attribute :cnpj, String
11
+ attribute :inscricao_municipal, String
12
+
13
+ def to_xml
14
+ xml = Builder::XmlMarkup.new(indent: 2)
15
+ xml.instruct!
16
+ xml.tag!("CancelarNfseEnvio", xmlns: "http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd") do |xml|
17
+ xml.tag!("Pedido", xmlns: "http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd") do |xml|
18
+ xml.tag!("InfPedidoCancelamento", Id: "Cancelamento_NF#{nf_number}") do |xml|
19
+ xml.tag!("IdentificacaoNfse") do |xml|
20
+ xml.tag!("Numero", nf_number)
21
+ xml.tag!("Cnpj", cnpj)
22
+ xml.tag!("InscricaoMunicipal", inscricao_municipal)
23
+ xml.tag!("CodigoMunicipio", SERVICO_CODIGO_MUNICIPIO[:RIO_DE_JANEIRO])
24
+ end
25
+ xml.tag!("CodigoCancelamento", "0")
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ module NFSeCarioca
2
+ class Configuration
3
+ include Singleton
4
+
5
+ attr_accessor :test_mode,
6
+ :ca_cert_pem_path,
7
+ :cert_key_pem_path,
8
+ :cert_pem_path,
9
+ :ssl_cert_key_password
10
+
11
+ def nota_carioca_wsdl_url
12
+ if test_mode
13
+ "https://homologacao.notacarioca.rio.gov.br/WSNacional/nfse.asmx?wsdl"
14
+ else
15
+ "https://notacarioca.rio.gov.br/WSNacional/nfse.asmx?wsdl"
16
+ end
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,49 @@
1
+ require "nfse_carioca/nota_carioca_response"
2
+ require "nfse_carioca/gerar_nfse_xml"
3
+
4
+ module NFSeCarioca
5
+ class GerarNFSe < NotaCariocaClient
6
+
7
+ def initialize(invoice)
8
+ @invoice = invoice
9
+ end
10
+
11
+ def execute!
12
+ Response.new(call(:gerar_nfse, nfse_xml))
13
+ end
14
+
15
+ def nfse_xml
16
+ GerarNFSeXML.new(@invoice).to_xml
17
+ end
18
+
19
+ class Response < NFSeCarioca::NotaCariocaResponse
20
+ def output_xml
21
+ @output_xml ||= @response.hash[:envelope][:body][:gerar_nfse_response][:output_xml]
22
+ end
23
+
24
+ def number
25
+ nota_carioca_xml["GerarNfseResposta"]["CompNfse"]["Nfse"]["InfNfse"]["Numero"] rescue nil
26
+ end
27
+
28
+ def verification_code
29
+ nota_carioca_xml["GerarNfseResposta"]["CompNfse"]["Nfse"]["InfNfse"]["CodigoVerificacao"] rescue nil
30
+ end
31
+
32
+ def issued_at
33
+ nota_carioca_xml["GerarNfseResposta"]["CompNfse"]["Nfse"]["InfNfse"]["DataEmissao"] rescue nil
34
+ end
35
+
36
+ def error?
37
+ !nota_carioca_xml["GerarNfseResposta"]["ListaMensagemRetorno"].nil?
38
+ end
39
+
40
+ def error_message
41
+ nota_carioca_xml["GerarNfseResposta"]["ListaMensagemRetorno"]["MensagemRetorno"]["Mensagem"] if error?
42
+ end
43
+
44
+ def success?
45
+ !error?
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,122 @@
1
+ module NFSeCarioca
2
+ class GerarNFSeXML
3
+ SERVICO_CODIGO_MUNICIPIO = {
4
+ RIO_DE_JANEIRO: "3304557"
5
+ }
6
+
7
+ RPS_SERIE = "A"
8
+
9
+ RPS_TIPO = {
10
+ RPS: 1
11
+ }
12
+
13
+ RPS_NATUREZA_OPERACAO = {
14
+ TRIBUTACAO_NO_MUNICIPIO: 1
15
+ }
16
+
17
+ RPS_OPTANTE_SIMPLES_NACIONAL = {
18
+ SIM: 1
19
+ }
20
+
21
+ RPS_INCENTIVADOR_CULTURAL = {
22
+ NAO: 2
23
+ }
24
+
25
+ RPS_STATUS = {
26
+ NORMAL: 1,
27
+ CANCELADO: 2
28
+ }
29
+
30
+
31
+ PROCON_DETAILS = <<-DESCRIPTION
32
+ Procon:
33
+ Telefone: 151
34
+ Endereço 1: Rua da Ajuda nº 5 subsolo - Centro
35
+ Endereço 2: Praça Cristiano Ottoni s/nº subsolo Ed. D. Pedro II Central do Brasil
36
+ Rio de janeiro RJ cep: 20221-250
37
+ Comissão de defesa do consumidor da Alerj
38
+ Telefone: 08002827060
39
+ Endereço: Rua da Alfandega nº 08 Térreo, Centro
40
+ Rio de janeiro - RJ Cep 20070-000
41
+ DESCRIPTION
42
+
43
+ VALOR_ISS_RETIDO = {
44
+ NAO: 2
45
+ }
46
+
47
+ VALOR_ALIQUOTA = "0.05"
48
+ VALOR_PIS = 0
49
+ VALOR_COFINS = 0
50
+ VALOR_INSS = 0
51
+ VALOR_IR = 0
52
+ VALOR_CSLL = 0
53
+ VALOR_ISS = 0
54
+
55
+ def initialize(invoice)
56
+ @invoice = invoice
57
+ end
58
+
59
+ def to_xml
60
+ xml = Builder::XmlMarkup.new(indent: 2)
61
+ xml.instruct!
62
+ xml.tag!("GerarNfseEnvio", xmlns: "http://notacarioca.rio.gov.br/WSNacional/XSD/1/nfse_pcrj_v01.xsd") do |xml|
63
+ xml.tag!("Rps") do |xml|
64
+ xml.tag!("InfRps", xmlns: "http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd", Id: @invoice.identification_number) do |xml|
65
+ xml.tag!("IdentificacaoRps") do |xml|
66
+ xml.tag!("Numero", @invoice.identification_number)
67
+ xml.tag!("Serie", RPS_SERIE)
68
+ xml.tag!("Tipo", RPS_TIPO[:RPS])
69
+ end
70
+ xml.tag!("DataEmissao", issued_at)
71
+ xml.tag!("NaturezaOperacao", RPS_NATUREZA_OPERACAO[:TRIBUTACAO_NO_MUNICIPIO])
72
+ xml.tag!("OptanteSimplesNacional", RPS_OPTANTE_SIMPLES_NACIONAL[:SIM])
73
+ xml.tag!("IncentivadorCultural", RPS_INCENTIVADOR_CULTURAL[:NAO])
74
+ xml.tag!("Status", RPS_STATUS[:NORMAL])
75
+ xml.tag!("Servico") do |xml|
76
+ xml.tag!("Valores") do |xml|
77
+ xml.tag!("ValorServicos", 0.1)
78
+ xml.tag!("ValorPis", VALOR_PIS)
79
+ xml.tag!("ValorCofins", VALOR_COFINS)
80
+ xml.tag!("ValorInss", VALOR_INSS)
81
+ xml.tag!("ValorIr", VALOR_IR)
82
+ xml.tag!("ValorCsll", VALOR_CSLL)
83
+ xml.tag!("IssRetido", VALOR_ISS_RETIDO[:NAO])
84
+ xml.tag!("ValorIss", VALOR_ISS)
85
+ xml.tag!("Aliquota", VALOR_ALIQUOTA)
86
+ end
87
+ xml.tag!("ItemListaServico", "0105")
88
+ xml.tag!("CodigoTributacaoMunicipio", "010501")
89
+ xml.tag!("Discriminacao", "#{@invoice.description}\n\n#{PROCON_DETAILS}")
90
+ xml.tag!("CodigoMunicipio", SERVICO_CODIGO_MUNICIPIO[:RIO_DE_JANEIRO])
91
+ end
92
+ xml.tag!("Prestador") do |xml|
93
+ xml.tag!("Cnpj", @invoice.provider.cnpj)
94
+ xml.tag!("InscricaoMunicipal", @invoice.provider.inscricao_municipal)
95
+ end
96
+ xml.tag!("Tomador") do |xml|
97
+ xml.tag!("IdentificacaoTomador") do |xml|
98
+ xml.tag!("CpfCnpj") do |xml|
99
+ xml.tag!(@invoice.customer.kind, @invoice.customer.code)
100
+ end
101
+ end
102
+ xml.tag!("RazaoSocial", @invoice.customer.full_name)
103
+ xml.tag!("Endereco") do |xml|
104
+ xml.tag!("Endereco", @invoice.customer.address.street)
105
+ xml.tag!("Numero", @invoice.customer.address.number)
106
+ xml.tag!("Complemento", @invoice.customer.address.complement)
107
+ xml.tag!("Bairro", @invoice.customer.address.neighborhood)
108
+ xml.tag!("CodigoMunicipio", @invoice.customer.address.city_ibge_code)
109
+ xml.tag!("Uf", @invoice.customer.address.state_code)
110
+ xml.tag!("Cep", @invoice.customer.address.zipcode)
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
117
+
118
+ def issued_at
119
+ Time.now.strftime("%Y-%m-%dT%H:%M:%S")
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,13 @@
1
+ module NFSeCarioca
2
+ class Address
3
+ include Virtus.model
4
+
5
+ attribute :street, String
6
+ attribute :number, String
7
+ attribute :complement, String
8
+ attribute :neighborhood, String
9
+ attribute :city_ibge_code, String
10
+ attribute :state_code, String
11
+ attribute :zipcode, String
12
+ end
13
+ end
@@ -0,0 +1,15 @@
1
+ require "nfse_carioca/models/address"
2
+
3
+ module NFSeCarioca
4
+ class Customer
5
+ include Virtus.model
6
+
7
+ attribute :kind, String
8
+ attribute :code, String
9
+ attribute :full_name, String
10
+ attribute :phone_number, String
11
+ attribute :email, String
12
+ attribute :address, Address
13
+
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ require "nfse_carioca/models/provider"
2
+ require "nfse_carioca/models/customer"
3
+
4
+ module NFSeCarioca
5
+ class Invoice
6
+ include Virtus.model
7
+
8
+ attribute :identification_number, String
9
+ attribute :description, String
10
+ attribute :provider, Provider
11
+ attribute :customer, Customer
12
+
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ module NFSeCarioca
2
+ class Provider
3
+ include Virtus.model
4
+
5
+ attribute :cnpj, String
6
+ attribute :inscricao_municipal, String
7
+
8
+ end
9
+ end
@@ -0,0 +1,31 @@
1
+ require "savon"
2
+
3
+ module NFSeCarioca
4
+ class NotaCariocaClient
5
+
6
+ def call(method, message)
7
+ client.call(method, message: { inputXML: message })
8
+ rescue Savon::HTTPError => e
9
+ p e
10
+ end
11
+
12
+ def client
13
+ @client ||= Savon.client({
14
+ wsdl: NFSeCarioca.nota_carioca_wsdl_url,
15
+ env_namespace: :soap,
16
+ namespace_identifier: nil,
17
+ element_form_default: :unqualified,
18
+ ssl_verify_mode: :none,
19
+ ssl_version: :SSLv3,
20
+ ssl_cert_file: NFSeCarioca.cert_pem_path,
21
+ ssl_cert_key_file: NFSeCarioca.cert_key_pem_path,
22
+ ssl_ca_cert_file: NFSeCarioca.ca_cert_pem_path,
23
+ ssl_cert_key_password: NFSeCarioca.ssl_cert_key_password,
24
+ log_level: :debug,
25
+ log: true,
26
+ open_timeout: 120,
27
+ read_timeout: 120
28
+ })
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ module NFSeCarioca
2
+ class NotaCariocaResponse
3
+
4
+ def initialize(response)
5
+ @response= response
6
+ end
7
+
8
+ def response_http_status
9
+ @response.http.code
10
+ end
11
+
12
+ def raw_response_soap_envelope
13
+ @response.xml
14
+ end
15
+
16
+ def nota_carioca_xml
17
+ @nota_carioca_xml ||= Hash.from_xml(output_xml)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,3 @@
1
+ module NFSeCarioca
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "nfse_carioca/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "nfse-carioca"
7
+ s.version = NFSeCarioca::VERSION
8
+ s.authors = ["LUZ Planilhas"]
9
+ s.email = ["bruno@luz.vc"]
10
+ s.summary = %q{Nota Fiscal de Serviço Eletronica}
11
+ s.description = %q{NFSeCarioca é um cliente ruby com foco na geração da Nota Carioca}
12
+ s.license = "MIT"
13
+
14
+ s.files = `git ls-files`.split("\n")
15
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
16
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
17
+ s.require_paths = ["lib"]
18
+
19
+ s.add_dependency "savon"
20
+ s.add_dependency "virtus", "~> 1.0.4"
21
+ s.add_dependency "builder", "~> 3.2.2"
22
+ s.add_dependency "activesupport", "~> 4.1"
23
+
24
+ s.add_development_dependency "bundler", "~> 1.7"
25
+ s.add_development_dependency "rake", "~> 10.0"
26
+ s.add_development_dependency "rspec"
27
+ s.add_development_dependency "pry"
28
+ end
@@ -0,0 +1,21 @@
1
+ <CancelarNfseResposta
2
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+ xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd">
5
+ <Cancelamento>
6
+ <Confirmacao Id="35514">
7
+ <Pedido>
8
+ <InfPedidoCancelamento Id="35514">
9
+ <IdentificacaoNfse>
10
+ <Numero>4</Numero>
11
+ <Cnpj>22220000000111</Cnpj>
12
+ <InscricaoMunicipal>4807995</InscricaoMunicipal>
13
+ <CodigoMunicipio>3304557</CodigoMunicipio>
14
+ </IdentificacaoNfse>
15
+ <CodigoCancelamento>9</CodigoCancelamento>
16
+ </InfPedidoCancelamento>
17
+ </Pedido>
18
+ <DataHoraCancelamento>2015-01-27T18:39:06</DataHoraCancelamento>
19
+ </Confirmacao>
20
+ </Cancelamento>
21
+ </CancelarNfseResposta>
@@ -0,0 +1,12 @@
1
+ <CancelarNfseResposta
2
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+ xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd">
5
+ <ListaMensagemRetorno>
6
+ <MensagemRetorno>
7
+ <Codigo>E78</Codigo>
8
+ <Mensagem>Número da NFSeCarioca inexistente na base de dados para o prestador de serviço pesquisado</Mensagem>
9
+ <Correcao>Informe o número correto da NFSeCarioca.</Correcao>
10
+ </MensagemRetorno>
11
+ </ListaMensagemRetorno>
12
+ </CancelarNfseResposta>
@@ -0,0 +1,85 @@
1
+ <GerarNfseResposta
2
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+ xmlns="http://notacarioca.rio.gov.br/WSNacional/XSD/1/nfse_pcrj_v01.xsd">
5
+ <CompNfse
6
+ xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd">
7
+ <Nfse>
8
+ <InfNfse>
9
+ <Numero>4</Numero>
10
+ <CodigoVerificacao>GSB9-BQU3</CodigoVerificacao>
11
+ <DataEmissao>2015-01-26T18:38:08</DataEmissao>
12
+ <IdentificacaoRps>
13
+ <Numero>18077</Numero>
14
+ <Serie>A</Serie>
15
+ <Tipo>1</Tipo>
16
+ </IdentificacaoRps>
17
+ <DataEmissaoRps>2015-01-26</DataEmissaoRps>
18
+ <NaturezaOperacao>1</NaturezaOperacao>
19
+ <OptanteSimplesNacional>1</OptanteSimplesNacional>
20
+ <IncentivadorCultural>2</IncentivadorCultural>
21
+ <Competencia>2015-01-26T00:00:00</Competencia>
22
+ <Servico>
23
+ <Valores>
24
+ <ValorServicos>0.1</ValorServicos>
25
+ <IssRetido>2</IssRetido>
26
+ <BaseCalculo>0.1</BaseCalculo>
27
+ <ValorLiquidoNfse>0.1</ValorLiquidoNfse>
28
+ </Valores>
29
+ <ItemListaServico>0105</ItemListaServico>
30
+ <CodigoTributacaoMunicipio>010501</CodigoTributacaoMunicipio>
31
+ <Discriminacao>TESTE TESTE
32
+
33
+ Procon:
34
+ Telefone: 151
35
+ Endereço 1: Rua da Ajuda nº 5 subsolo - Centro
36
+ Endereço 2: Praça Cristiano Ottoni s/nº subsolo Ed. D. Pedro II Central do Brasil
37
+ Rio de janeiro RJ cep: 20221-250
38
+ Comiss\u00E3o de defesa do consumidor da Alerj
39
+ Telefone: 08002827060
40
+ Endereço: Rua da Alfandega nº 08 Térreo, Centro
41
+ Rio de janeiro - RJ Cep 20070-000
42
+ </Discriminacao>
43
+ <CodigoMunicipio>3304557</CodigoMunicipio>
44
+ </Servico>
45
+ <PrestadorServico>
46
+ <IdentificacaoPrestador>
47
+ <Cnpj>11110095000111</Cnpj>
48
+ <InscricaoMunicipal>4807995</InscricaoMunicipal>
49
+ </IdentificacaoPrestador>
50
+ <RazaoSocial>LLDIL EPP</RazaoSocial>
51
+ <Endereco>
52
+ <Endereco>RUA QUALQUER 93</Endereco>
53
+ <Numero>93</Numero>
54
+ <Bairro>BAIRRO</Bairro>
55
+ <CodigoMunicipio>3304557</CodigoMunicipio>
56
+ <Uf>RJ</Uf>
57
+ <Cep>22200111</Cep>
58
+ </Endereco>
59
+ <Contato />
60
+ </PrestadorServico>
61
+ <TomadorServico>
62
+ <IdentificacaoTomador>
63
+ <CpfCnpj>
64
+ <Cnpj>55553333000111</Cnpj>
65
+ </CpfCnpj>
66
+ </IdentificacaoTomador>
67
+ <RazaoSocial>XPT Tecnologia e Desenvolvimento - LTDA</RazaoSocial>
68
+ <Endereco>
69
+ <Endereco>Rua da avenida</Endereco>
70
+ <Numero>116</Numero>
71
+ <Complemento>SALA 1</Complemento>
72
+ <Bairro>Vila vila</Bairro>
73
+ <CodigoMunicipio>3550308</CodigoMunicipio>
74
+ <Uf>SP</Uf>
75
+ <Cep>5550055</Cep>
76
+ </Endereco>
77
+ </TomadorServico>
78
+ <OrgaoGerador>
79
+ <CodigoMunicipio>3304557</CodigoMunicipio>
80
+ <Uf>RJ</Uf>
81
+ </OrgaoGerador>
82
+ </InfNfse>
83
+ </Nfse>
84
+ </CompNfse>
85
+ </GerarNfseResposta>
@@ -0,0 +1,13 @@
1
+ <GerarNfseResposta
2
+ xmlns:xsd="http://www.w3.org/2001/XMLSchema"
3
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4
+ xmlns="http://notacarioca.rio.gov.br/WSNacional/XSD/1/nfse_pcrj_v01.xsd">
5
+ <ListaMensagemRetorno
6
+ xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd">
7
+ <MensagemRetorno>
8
+ <Codigo>E10</Codigo>
9
+ <Mensagem>RPS já informado.</Mensagem>
10
+ <Correcao>Para essa Inscrição Municipal/CNPJ já existe um RPS informado com o mesmo número, série e tipo. </Correcao>
11
+ </MensagemRetorno>
12
+ </ListaMensagemRetorno>
13
+ </GerarNfseResposta>
@@ -0,0 +1,48 @@
1
+ RSpec.describe NFSeCarioca::CancelarNFSe do
2
+
3
+ describe "#execute!" do
4
+
5
+ context 'when NFSeCarioca rps number does not exist' do
6
+ let(:invoice_canceller) do
7
+ described_class.new(rps_number: "0018070",
8
+ cnpj: "12390095000186",
9
+ inscricao_municipal: "04807995")
10
+ end
11
+
12
+ before do
13
+ mock_response = SavonResponseMock.new(:cancelar_nfse_response, soap_response("CancelarNfseRespostaE78.xml"))
14
+ allow_any_instance_of(described_class).to receive(:call).and_return(mock_response)
15
+ end
16
+
17
+ let(:response) { invoice_canceller.execute! }
18
+
19
+ it 'returns false' do
20
+ expect(response.success?).to be_falsy
21
+ end
22
+
23
+ it 'returns error message' do
24
+ expect(response.error_message).to eq "Informe o número correto da NFSeCarioca."
25
+ end
26
+ end
27
+
28
+ context 'when NFSeCarioca rps number exist' do
29
+ let(:invoice_canceller) do
30
+ described_class.new(nf_number: "00000004",
31
+ cnpj: "12390095000186",
32
+ inscricao_municipal: "04807995")
33
+ end
34
+
35
+ before do
36
+ mock_response = SavonResponseMock.new(:cancelar_nfse_response, soap_response("CancelarNfseResposta.xml"))
37
+ allow_any_instance_of(described_class).to receive(:call).and_return(mock_response)
38
+ end
39
+
40
+ let(:response) { invoice_canceller.execute! }
41
+
42
+ it 'returns false' do
43
+ expect(response.success?).to be_truthy
44
+ end
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,49 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe 'Configuration' do
4
+ context 'when not configured' do
5
+ before(:each) do
6
+ NFSeCarioca.configure do |config|
7
+ config.test_mode = false
8
+
9
+ config.cert_pem_path = nil
10
+ config.ca_cert_pem_path = nil
11
+ config.cert_key_pem_path = nil
12
+ config.ssl_cert_key_password = nil
13
+ end
14
+ end
15
+
16
+ after(:each) do
17
+ NFSeCarioca.reset
18
+ end
19
+
20
+ it { expect(NFSeCarioca.cert_pem_path).to be_nil }
21
+ it { expect(NFSeCarioca.ca_cert_pem_path).to be_nil }
22
+ it { expect(NFSeCarioca.cert_key_pem_path).to be_nil }
23
+ it { expect(NFSeCarioca.ssl_cert_key_password).to be_nil }
24
+ it { expect(NFSeCarioca.nota_carioca_wsdl_url).to eq "https://notacarioca.rio.gov.br/WSNacional/nfse.asmx?wsdl" }
25
+ end
26
+
27
+ context 'when configured' do
28
+ before(:each) do
29
+ NFSeCarioca.configure do |config|
30
+ config.test_mode = true
31
+
32
+ config.cert_pem_path = "/my/string/path/to/certicate.pem"
33
+ config.ca_cert_pem_path = "/my/string/path/to/ca/certicate.pem"
34
+ config.cert_key_pem_path = "/my/string/path/to/certicate/key.pem"
35
+ config.ssl_cert_key_password = "very-secure-encrypted-password"
36
+ end
37
+ end
38
+
39
+ after(:each) do
40
+ NFSeCarioca.reset
41
+ end
42
+
43
+ it { expect(NFSeCarioca.cert_pem_path).to eq "/my/string/path/to/certicate.pem" }
44
+ it { expect(NFSeCarioca.ca_cert_pem_path).to eq "/my/string/path/to/ca/certicate.pem" }
45
+ it { expect(NFSeCarioca.cert_key_pem_path).to eq "/my/string/path/to/certicate/key.pem" }
46
+ it { expect(NFSeCarioca.ssl_cert_key_password).to eq "very-secure-encrypted-password" }
47
+ it { expect(NFSeCarioca.nota_carioca_wsdl_url).to eq "https://homologacao.notacarioca.rio.gov.br/WSNacional/nfse.asmx?wsdl" }
48
+ end
49
+ end
@@ -0,0 +1,107 @@
1
+ RSpec.describe NFSeCarioca::GerarNFSe do
2
+ let(:nota_fiscal_info) do
3
+ {
4
+ identification_number: "01",
5
+ description: "Venda do Serviço XYZ.",
6
+ provider: {
7
+ cnpj: "11199990000111",
8
+ inscricao_municipal: "04807995"
9
+ },
10
+ customer: {
11
+ kind: "Cnpj",
12
+ code: "22220099000111",
13
+ full_name: "XPTO Tecnologia Ltda.",
14
+ phone_number: "2222-2222", #opcional
15
+ email: "customer@example.com", #opcional
16
+ address: {
17
+ street: "Rua qualquer nome",
18
+ number: "33",
19
+ complement: "Sala 1",
20
+ neighborhood: "Seu bairro",
21
+ city_ibge_code: "3550308",
22
+ state_code: "SP",
23
+ zipcode: "22255777"
24
+ }
25
+ }
26
+ }
27
+ end
28
+
29
+ let(:invoice) { NFSeCarioca::Invoice.new(nota_fiscal_info) }
30
+
31
+ let!(:invoice_generator) { described_class.new(invoice) }
32
+
33
+ describe '#nfse_xml' do
34
+ let(:xml) { invoice_generator.nfse_xml }
35
+
36
+
37
+ it 'contains correct identification number' do
38
+ expect(xml).to include %{<Numero>01</Numero>}
39
+ end
40
+
41
+ it 'contains correct description' do
42
+ expect(xml).to include %{<Discriminacao>Venda do Serviço XYZ.}
43
+ end
44
+
45
+ it 'contains correct provider information' do
46
+ expect(xml).to include %{<Prestador>
47
+ <Cnpj>11199990000111</Cnpj>
48
+ <InscricaoMunicipal>04807995</InscricaoMunicipal>
49
+ </Prestador>}
50
+ end
51
+
52
+ it 'contains correct customer information' do
53
+ expect(xml).to include %{
54
+ <IdentificacaoTomador>
55
+ <CpfCnpj>
56
+ <Cnpj>22220099000111</Cnpj>
57
+ </CpfCnpj>
58
+ </IdentificacaoTomador>
59
+ <RazaoSocial>XPTO Tecnologia Ltda.</RazaoSocial>
60
+ <Endereco>
61
+ <Endereco>Rua qualquer nome</Endereco>
62
+ <Numero>33</Numero>
63
+ <Complemento>Sala 1</Complemento>
64
+ <Bairro>Seu bairro</Bairro>
65
+ <CodigoMunicipio>3550308</CodigoMunicipio>
66
+ <Uf>SP</Uf>
67
+ <Cep>22255777</Cep>
68
+ </Endereco>}
69
+ end
70
+ end
71
+
72
+ describe "#call" do
73
+ context 'when NFSeCarioca rps number does not exist yet' do
74
+ before do
75
+ mock_response = SavonResponseMock.new(:gerar_nfse_response, soap_response("GerarNfseResposta.xml"))
76
+ allow_any_instance_of(described_class).to receive(:call).and_return(mock_response)
77
+ end
78
+
79
+ let(:response) { invoice_generator.execute! }
80
+
81
+ it 'generates NFSeCarioca number' do
82
+ expect(response.number).to eq "4"
83
+ end
84
+
85
+ it 'generates NFSeCarioca verification code' do
86
+ expect(response.verification_code).to eq "GSB9-BQU3"
87
+ end
88
+ end
89
+
90
+ context 'when NFSeCarioca rps number already exist' do
91
+ before do
92
+ mock_response = SavonResponseMock.new(:gerar_nfse_response, soap_response("GerarNfseRespostaE10.xml"))
93
+ allow_any_instance_of(described_class).to receive(:call).and_return(mock_response)
94
+ end
95
+
96
+ let(:response) { invoice_generator.execute! }
97
+
98
+ it "responds with error" do
99
+ expect(response.error?).to be_truthy
100
+ end
101
+
102
+ it "responds with message error E10 " do
103
+ expect(response.error_message).to eq "RPS já informado."
104
+ end
105
+ end
106
+ end
107
+ end
@@ -0,0 +1,34 @@
1
+ require 'bundler'
2
+ Bundler.setup
3
+
4
+ require "nfse_carioca"
5
+ require "pry"
6
+
7
+ Dir[File.join(File.dirname(__FILE__), '/support/**/*.rb')].each { |f| require f }
8
+
9
+ RSpec.configure do |config|
10
+ config.expect_with :rspec do |expectations|
11
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
12
+ end
13
+
14
+ config.mock_with :rspec do |mocks|
15
+ mocks.verify_partial_doubles = true
16
+ end
17
+
18
+ config.filter_run :focus
19
+ config.run_all_when_everything_filtered = true
20
+
21
+ config.disable_monkey_patching!
22
+
23
+ config.warnings = true
24
+
25
+ if config.files_to_run.one?
26
+ config.default_formatter = 'doc'
27
+ end
28
+
29
+ config.profile_examples = 5
30
+
31
+ config.order = :random
32
+
33
+ Kernel.srand config.seed
34
+ end
@@ -0,0 +1,21 @@
1
+ def file_path(filename)
2
+ File.expand_path("../../fixtures/#{filename}", __FILE__)
3
+ end
4
+
5
+ SavonResponseMock = Struct.new(:key, :content) do
6
+ def hash
7
+ {
8
+ envelope: {
9
+ body: {
10
+ "#{key}": {
11
+ output_xml: content
12
+ }
13
+ }
14
+ }
15
+ }
16
+ end
17
+ end
18
+
19
+ def soap_response(filename)
20
+ output_xml = IO.read(file_path("nota_carioca/#{filename}"))
21
+ end
metadata ADDED
@@ -0,0 +1,186 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: nfse-carioca
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - LUZ Planilhas
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: savon
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: virtus
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.0.4
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.0.4
41
+ - !ruby/object:Gem::Dependency
42
+ name: builder
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 3.2.2
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 3.2.2
55
+ - !ruby/object:Gem::Dependency
56
+ name: activesupport
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '4.1'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '4.1'
69
+ - !ruby/object:Gem::Dependency
70
+ name: bundler
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.7'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.7'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '10.0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '10.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: pry
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ description: NFSeCarioca é um cliente ruby com foco na geração da Nota Carioca
126
+ email:
127
+ - bruno@luz.vc
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".gitignore"
133
+ - ".rspec"
134
+ - CHANGELOG.md
135
+ - CONTRIBUTING.md
136
+ - Gemfile
137
+ - README.md
138
+ - Rakefile
139
+ - lib/nfse_carioca.rb
140
+ - lib/nfse_carioca/cancelar_nfse.rb
141
+ - lib/nfse_carioca/cancelar_nfse_xml.rb
142
+ - lib/nfse_carioca/configuration.rb
143
+ - lib/nfse_carioca/gerar_nfse.rb
144
+ - lib/nfse_carioca/gerar_nfse_xml.rb
145
+ - lib/nfse_carioca/models/address.rb
146
+ - lib/nfse_carioca/models/customer.rb
147
+ - lib/nfse_carioca/models/invoice.rb
148
+ - lib/nfse_carioca/models/provider.rb
149
+ - lib/nfse_carioca/nota_carioca_client.rb
150
+ - lib/nfse_carioca/nota_carioca_response.rb
151
+ - lib/nfse_carioca/version.rb
152
+ - nfse_carioca.gemspec
153
+ - spec/fixtures/nota_carioca/CancelarNfseResposta.xml
154
+ - spec/fixtures/nota_carioca/CancelarNfseRespostaE78.xml
155
+ - spec/fixtures/nota_carioca/GerarNfseResposta.xml
156
+ - spec/fixtures/nota_carioca/GerarNfseRespostaE10.xml
157
+ - spec/lib/nfse_carioca/cancelar_nfse_spec.rb
158
+ - spec/lib/nfse_carioca/configuration_spec.rb
159
+ - spec/lib/nfse_carioca/gerar_nfse_spec.rb
160
+ - spec/spec_helper.rb
161
+ - spec/support/helpers.rb
162
+ homepage:
163
+ licenses:
164
+ - MIT
165
+ metadata: {}
166
+ post_install_message:
167
+ rdoc_options: []
168
+ require_paths:
169
+ - lib
170
+ required_ruby_version: !ruby/object:Gem::Requirement
171
+ requirements:
172
+ - - ">="
173
+ - !ruby/object:Gem::Version
174
+ version: '0'
175
+ required_rubygems_version: !ruby/object:Gem::Requirement
176
+ requirements:
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ version: '0'
180
+ requirements: []
181
+ rubyforge_project:
182
+ rubygems_version: 2.4.5
183
+ signing_key:
184
+ specification_version: 4
185
+ summary: Nota Fiscal de Serviço Eletronica
186
+ test_files: []