Project

br_nfe

0.05
No commit activity in last 3 years
No release in over 3 years
BrNfe é uma gem para projetos Ruby on Rails que tem como objetifo facilitar e padronizar a emissão de Notas Fiscais eletrônicas
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

~> 0.10

Runtime

~> 1.6
~> 10
~> 2.11
~> 1.4
~> 3.0
 Project Readme

Build Status Test Coverage Gem Version Code Climate

BrNfe

Gem para emissão de notas fiscais eletrônicas.

Motivação

Devido a falta de padronização dos parâmetros e a forma de envio e resposta na transmissão de Notas Fiscais de Serviços (NFS-e), esta gem vem com o objetivo de obter uma forma padronizada dessa tarefa, e assim, facilitando a vida de muitos desenvolvedores.

A Nota Fiscal eletrônica de produto está em desenvolvimento e pode ser acompanhada através da issue #4

O que essa gem faz?

  • Assina digitalmente a nota fiscal eletrônica.
  • Envia os parâmetros com a formatação adequada conforme documentação de cada web service desenvolvido.
  • Formata em um padrão único a resposta de cada web service.
  • Valida (opcionalmente) a obrigatoriedade de cada informação a ser enviada.

Instalação

Manualmente

gem install br_nfe

Gemfile

 gem 'br_nfe'

#Introdução Com o objetivo de padronizar os valores, foi criado algumas classes auxiliares para montar e organizar os dados para a emissão das notas fiscais, dentre eles estão:

  • BrNfe::Endereco -- Tem o objetivo de padronizar os dados de endereço para o emitente e destinatário.

####Específico para NFS-e:

  • BrNfe::Service::Emitente -- Classe para instanciar o emitente da nota fiscal de serviço (NFS-e). -- Contém as validações e regras para o mesmo. -- Contém uma "Associação" com BrNfe::Endereco
  • BrNfe::Service::Destinatario -- Classe para instanciar o destinatário da nota fiscal de serviço (NFS-e). -- Contém as validações e regras para o mesmo. -- Contém uma "Associação" com BrNfe::Endereco

  • BrNfe::Service::Intermediario -- Classe para instanciar o intermediário na nota fiscal de serviço (NFS-e). -- Contém as validações e regras para o mesmo.

  • BrNfe::Service::Item -- Item da nota fiscal de serviço; -- Alguns órgãos emissores permitem adicionar vários itens de serviço na NFS. -- Ainda, para alguns emissores é obrigatório a definição de itens de serviço, porém para outros esse item não é necessário.

  • BrNfe::Service::Rps -- Classe para instanciar o RPS (Recibo Provisório de Serviço). -- Contém as validações e regras para o mesmo. -- Contém "Associação" com BrNfe::Service::Destinatario e BrNfe::Service::Intermediario -- Contém vários BrNfe::Service::Item através do atributo items

Como citado anteriormente, essas são classes para objetos auxiliares, e serão utilizados para manter uma melhor organização da gem.

##Entendendo a organização da gem

Primeiramente é necessário ter conhecimento das operações disponíveis para cada tipo de Nota Fiscal. Vamos a elas:

Notas Fiscais de Serviço (NFS)

Existe uma certa "padronização" das operações desenvolvidas pelos Órgãos Emissores¹. São elas:

  • Cancelamento de NFS (Utilizado para cancelar uma NFS)
  • Consulta do Lote RPS (Utilizado para consultar um lote de RPS)
  • Consulta de NFS por RPS (Utilizado para consultar uma NFS através dos dados do RPS)
  • Consulta NFS (Utilizado para consultar uma ou várias NFS através do número e/ou data)
  • Consulta Situação do lote RPS (Utilizado para consultar a situação de um lote de RPS para verificar se foi processado e se foi processado com sucesso ou erro)
  • Recepção do lote RPS (Utilizado enviar RPS's para emissão de NFS)

Através destas operações, serão instanciados os objetos para realizar as funcionalidades para cada atividade.

Cada cidade contrata um órgão emissor para o processamento das notas (ou pode ser que a própria prefeitura desenvolva), então para realizar as operações para cada cidade, você deverá saber qual a empresa contratada para esse fim, e então instanciar o objeto de acordo com sua necessidade. A seguir segue o padrão para instanciar os objetos para cada operação:

  • Para Cancelamento de NFS:
	BrNfe::Service::ORGAO_EMISSOR::VERSAO_DO_XML::CancelaNfse.new(...)
  • Para Consulta do Lote RPS:
BrNfe::Service::ORGAO_EMISSOR::VERSAO_DO_XML::ConsultaLoteRps.new(...)
  • Para Consulta de NFS por RPS:
BrNfe::Service::ORGAO_EMISSOR::VERSAO_DO_XML::ConsultaNfsPorRps.new(...)
  • Para Consulta NFS:
BrNfe::Service::ORGAO_EMISSOR::VERSAO_DO_XML::ConsultaNfse.new(...)
  • Para Consulta Situação do lote RPS:
BrNfe::Service::ORGAO_EMISSOR::VERSAO_DO_XML::ConsultaSituacaoLoteRps.new(...)
  • Para Recepção do lote RPS:
BrNfe::Service::ORGAO_EMISSOR::VERSAO_DO_XML::RecepcaoLoteRps.new(...)

Para enviar os dados para processamento deve ser chamado o método request, no qual será enviado os dados via XML para o órgão emissor correspondente.

Se desejar, antes de enviar os dados, o objeto poderá ser validado, EX:

@ws = BrNfe::Service::ORGAO_EMISSOR::V1::ConsultaLoteRps.new(...)
if @ws.valid?
	@ws.request
	@response = @ws.response
else
	# Tratamento da validação
end

O resultado obtido na variável @response é um objeto com os dados pertinentes e derivados de cada operação, por exemplo, se eu utilizar a operação de RecepcaoLoteRps, então a resposta será um objeto da classe BrNfe::Service::Response::RecepcaoLoteRps, na qual tem as informações obtidas pela resposta dessa operação. Já para a operação ConsultaLoteRps a resposta é um objeto da classe BrNfe::Service::Response::ConsultaLoteRps, e assim segue para cada operação. (para ver exemplos das respostas obtidas a cada operação, consulte a wiki).

Se desejar, é possível obter a resposta original (do savon) de cada órgão emissor através do método original_response.

###Instanciando e manipulando objetos

Em todas as classes desenvolvidas é possível instanciar objetos em forma de Hash ou Block. Veja:

# Hash
@endereco = BrNfe::Endereco.new({
	logradouro: "RUA FERNANDO MACHADO",
	numero: 369,
	complemento: "E",
	# ...
})

# Block
@endereco = BrNfe::Endereco.new do |endereco|
	endereco.logradouro = "RUA FERNANDO MACHADO"
	endereco.numero = 369
	endereco.complemento = "E"
	# ...
})

As associações também podem ser instanciadas em forma de Hash ou Block, e ainda pode ser setado o objeto diretamente. Exemplo:

# Hash
@emitente = BrNfe::Service::Emitente.new({
	cnpj: '11.111.111/1111-00',
	...
	endereco: {
		logradouro: "RUA FERNANDO MACHADO",
		numero: 369,
		complemento: "E",
		...
	}
})
# Block
@emitente = BrNfe::Service::Emitente.new do |emitente|
	emitente.cnpj = '11.111.111/1111-00'
	...
	emitente.endereco do |address|
		address.logradouro  = "RUA FERNANDO ...",
		address.numero      = 369,
		address.complemento = "E",
		...
	end
	# OU
	# emitente.endereco = {
	#	logradouro: "RUA FERNANDO ...",
	#	numero: 369,
	#	complemento: "E",
	#	...
	# }
end

# Setando o objeto
@endereco = BrNfe::Endereco.new(rua: "RUA DOS PRAZERES",...)
@emitente = BrNfe::Service::Emitente.new(razao_social: 'Emitente LTDA', endereco: @endereco)

Também é possível fazer o merge dos atributos através do método assign_attributes, por exemplo:

@endereco = BrNfe::Endereco.new({
	logradouro: "RUA 1",
	numero: 100,
	uf: 'SC'
})
@endereco.logradouro
# => "RUA 1"
@endereco.numero
# => 100
@endereco.uf
# => "SC"

@endereco.assign_attributes(numero: 200, uf: 'RS')
@endereco.logradouro
# => "RUA 1"
@endereco.numero
# => 200
@endereco.uf
# => "RS"

Exemplo para Recepção de um Lote RPS:

Endereço:

@endereco = BrNfe::Endereco.new({
	logradouro: "RUA FERNANDO MACHADO",
	numero: 369,
	complemento: "E",
	bairro: "CENTRO",
	nome_municipio: "CHAPECÓ",
	codigo_municipio: 4204202,
	uf: "SC",
	cep: "89665-000",
	# codigo_pais: 1058, <- Default
	# nome_pais: 'BRASIL', <- Default
})

Emitente:

@emitente = BrNfe::Service::Emitente.new({
	cnpj: '11.111.111/1111-00',
	inscricao_municipal: '66165-4',
	razao_social: 'RAZÃO SOCIAL',
	natureza_operacao: '1',
	nome_fantasia: 'NOME FANTASIA',
	telefone: '4933665577',
	email: 'emitente@mail.com',
	regime_especial_tributacao: '1',
	codigo_regime_tributario: '1', # 1: Simples Nacional, 2: Simples Nacional(sublimite), 3: Reg. Normal
	incentivo_fiscal: false,
	endereco: @endereco
})

Lembrando que por padrão, sempre que for chamar @emitente.endereco irá retornar um objeto da class BrNfe::Endereco, mesmo que não seja setado valor algum, ex:

@emitente = BrNfe::Service::Emitente.new
@emitente.endereco
# => #<BrNfe::Endereco:0x000000022669a0 @codigo_pais="1058",  ....>

Destinatário

@destinatario = BrNfe::Service::Destinatario.new({
	cpf_cnpj: "111.111.111-00",
	inscricao_municipal: "",
	inscricao_estadual:  "",
	inscricao_suframa:   "",
	razao_social: "NOME DA PESSOA OU EMPRESA",
	nome_fantasia: "",
	telefone: "3365478",
	email: "destinatario@mail.com",
	endereco: {
		logradouro: "RUA AUGUSTO VILA LOBO",
	numero: 45,
	complemento: "E",
	bairro: "CENTRO",
	nome_municipio: "FLORIANÓPOLIS",
	codigo_municipio: '4205407',
	uf: "SC",
	cep: "89665-000",
	}
})

Condição de pagamento

@condicao_pagamento = BrNfe::CondicaoPagamento.new do |cond|
	cond.condicao = 'A_PRAZO' # ou 'A_VISTA'
	cond.parcelas = [
		{valor: 50.33, vencimento: Date.today}, 
		{valor: '27.00', vencimento: 1.month.since}
	]
end

Intermediário do serviço

@intermediario = BrNfe::Service::Intermediario.new({
	cpf_cnpj: '11.111.111/0001-36',
	inscricao_municipal: '3355-6',
	razao_social: "INTERMEDIÁRIO DO SERVIÇO"
})

RPS

@rps = BrNfe::Service::Rps.new do |rps|
	rps.destinatario  = @destinatario
	rps.intermediario = @intermediario
	rps.condicao_pagamento  =  @condicao_pagamento
	rps.numero                  = 5525
	rps.serie                   = "SN"
	rps.tipo                    = "1"
	rps.data_emissao            = DateTime.now
	rps.status                  = "1"
	rps.competencia             = DateTime.now
	rps.numero_substituicao     = "5524"
	rps.serie_substituicao      = "SN"
	rps.tipo_substituicao       = "1"
	rps.valor_servicos          = 100.00
	rps.valor_deducoes          = "0"
	rps.valor_pis               = "0"
	rps.valor_iss               = 2.0
	rps.aliquota                = 0.02 # = 2%
	rps.base_calculo            = "100.00"
	rps.item_lista_servico      = "1.07"
	rps.discriminacao           = "1 Configuração de servidor: R$ 500.00"
	rps.exigibilidade_iss       = "1"
	rps.codigo_municipio        = "4204202"
	rps.municipio_incidencia    = "4204202"
end

RecepcaoLoteRps (Com o órgão emissor Betha)

@recepcao = BrNfe::Service::Betha::V1::RecepcaoLoteRps.new do |ws|
	ws.emitente = @emitente
	ws.lote_rps = [@rps]
	ws.numero_lote_rps = 214
	ws.env = :production # OU :test
	ws.certificate_pkcs12_path  = '/path/to/certificate.pfx'
	wx.certificate_pkcs12_password = 'PASSWORD'
end

@recepcao.request
resp = @recepcao.response
#=> #<BrNfe::Service::Response::RecepcaoLoteRps:0x000016a9e28 ...>

resp.protocolo
#=> 'EX456156E'

resp.data_recebimento
#=> Fri, 23 Sep 2015 17:40:15 -0300

resp.numero_lote
#=> 214

Para demais operações consulte a WiKi.

Configurações

É possível customizar as classes auxiliares, por exemplo, se você quiser fazer alguma validação específica para o endereço, que contenha os mesmo atributos, você deve criar sua própria class e setar na configuração da gem qual será a classe que irá representar o endereço. Exemplo:

class MeuEndereco < BrNfe::Endereco
	validates :cep, length: { is: 8 }
end

emitente = BrNfe::Service::Emitente.new
emitente.endereco
#=> #<BrNfe::Endereco:0x000000016741d8 @codigo_pais="1058", @nome_pais="BRASIL">

BrNfe.endereco_class = MeuEndereco

emitente = BrNfe::Service::Emitente.new
emitente.endereco
#=> #<MeuEndereco:0x000000016741d8 @codigo_pais="1058", @nome_pais="BRASIL">

Segue as configurações possíveis

BrNfe.setup do |config|
	# Classe que representa o endereço
	config.endereco_class = BrNfe::Endereco
	
	# Classe que representa os emitentes para NFS
	config.emitente_service_class = BrNfe::Service::Emitente
	
	# Classe que representa o destinatário para NFS
	config.destinatario_service_class = BrNfe::Service::Destinatario
	
	# Classe que representa o intermediário da NFS
	config.intermediario_service_class = BrNfe::Service::Intermediario

	# Classe que representa a condição de pagamento da NFS
	config.condicao_pagamento_class = BrNfe::CondicaoPagamento
	
	# Classe que representa o RPS da NFS
	config.rps_class = BrNfe::Service::Rps

	# Classe que representa o item de uma NFS
	config.service_item_class = BrNfe::Service::Item
	
	# Se você quiser exibir em log a requisição SOAP, mude para true as opções a seguir
	config.client_wsdl_log = false
	config.client_wsdl_pretty_print_xml = false
end

Objetivos futuros

  • Emitir notas fiscais de produtos (em andamento).
  • Emitir notas fiscais de serviços para todas as cidades do Brasil.
  • Emitir DANFE.
  • Leitura de notas fiscais de produto e serviço

Contribuições

Seja um contribuidor. Você pode contribuir de várias formas:

  • Desenvolver emissão de NFS-e para outras cidades.
  • Desenvolver emissão de NF-e (produtos).
  • Refatorando código.
  • Fornecendo Feedback construtivo (Sempre bem vindo!).

Licença

  • MIT
  • Copyleft 2016 Bruno Mucelini Mergen

¹ **Órgão Emissor: ** É a empresa contratada pela prefeitura com a finalidade de processar as notas fiscais. Exemplo: (Betha, Simpliss, Thema)