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 +7 -0
- data/.gitignore +20 -0
- data/.rspec +2 -0
- data/CHANGELOG.md +7 -0
- data/CONTRIBUTING.md +35 -0
- data/Gemfile +3 -0
- data/README.md +91 -0
- data/Rakefile +11 -0
- data/lib/nfse_carioca.rb +28 -0
- data/lib/nfse_carioca/cancelar_nfse.rb +36 -0
- data/lib/nfse_carioca/cancelar_nfse_xml.rb +31 -0
- data/lib/nfse_carioca/configuration.rb +20 -0
- data/lib/nfse_carioca/gerar_nfse.rb +49 -0
- data/lib/nfse_carioca/gerar_nfse_xml.rb +122 -0
- data/lib/nfse_carioca/models/address.rb +13 -0
- data/lib/nfse_carioca/models/customer.rb +15 -0
- data/lib/nfse_carioca/models/invoice.rb +14 -0
- data/lib/nfse_carioca/models/provider.rb +9 -0
- data/lib/nfse_carioca/nota_carioca_client.rb +31 -0
- data/lib/nfse_carioca/nota_carioca_response.rb +20 -0
- data/lib/nfse_carioca/version.rb +3 -0
- data/nfse_carioca.gemspec +28 -0
- data/spec/fixtures/nota_carioca/CancelarNfseResposta.xml +21 -0
- data/spec/fixtures/nota_carioca/CancelarNfseRespostaE78.xml +12 -0
- data/spec/fixtures/nota_carioca/GerarNfseResposta.xml +85 -0
- data/spec/fixtures/nota_carioca/GerarNfseRespostaE10.xml +13 -0
- data/spec/lib/nfse_carioca/cancelar_nfse_spec.rb +48 -0
- data/spec/lib/nfse_carioca/configuration_spec.rb +49 -0
- data/spec/lib/nfse_carioca/gerar_nfse_spec.rb +107 -0
- data/spec/spec_helper.rb +34 -0
- data/spec/support/helpers.rb +21 -0
- metadata +186 -0
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
data/.rspec
ADDED
data/CHANGELOG.md
ADDED
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
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
data/lib/nfse_carioca.rb
ADDED
|
@@ -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,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,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
|
data/spec/spec_helper.rb
ADDED
|
@@ -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: []
|