nfse-carioca 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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: []