Class: BrNfe::Base

Inherits:
ActiveModelBase show all
Includes:
Association::HaveEmitente
Defined in:
lib/br_nfe/base.rb

Direct Known Subclasses

Product::Operation::Base, Service::Base

Instance Attribute Summary collapse

Attributes inherited from ActiveModelBase

#reference

Instance Method Summary collapse

Methods included from Association::HaveEmitente

#emitente, #emitente=

Methods inherited from ActiveModelBase

#assign_attributes, #default_values, #initialize

Constructor Details

This class inherits a constructor from BrNfe::ActiveModelBase

Instance Attribute Details

#certificate_pkcs12_passwordObject

Returns the value of attribute certificate_pkcs12_password.



5
6
7
# File 'lib/br_nfe/base.rb', line 5

def certificate_pkcs12_password
  @certificate_pkcs12_password
end

#certificate_pkcs12_pathObject

Returns the value of attribute certificate_pkcs12_path.



6
7
8
# File 'lib/br_nfe/base.rb', line 6

def certificate_pkcs12_path
  @certificate_pkcs12_path
end

#certificate_pkcs12_valueObject

Caso não tenha o certificate_pkcs12 salvo em arquivo, pode setar a string do certificate_pkcs12 direto pelo atributo certificate_pkcs12_value Caso tenha o certificate_pkcs12 em arquivo, basta setar o atributo certificate_pkcs12_path e deixar o atributo certificate_pkcs12_value em branco



197
198
199
# File 'lib/br_nfe/base.rb', line 197

def certificate_pkcs12_value
  @certificate_pkcs12_value
end

#envObject

Returns the value of attribute env.



8
9
10
# File 'lib/br_nfe/base.rb', line 8

def env
  @env
end

#ibge_code_of_issuer_cityObject

Código IBGE da cidade emitente



11
12
13
# File 'lib/br_nfe/base.rb', line 11

def ibge_code_of_issuer_city
  @ibge_code_of_issuer_city
end

#ibge_code_of_issuer_ufObject

Código IBGE do estado emitente



17
18
19
# File 'lib/br_nfe/base.rb', line 17

def ibge_code_of_issuer_uf
  @ibge_code_of_issuer_uf
end

Instance Method Details

#certificado_obrigatorio?Boolean

Método que deve ser sobrescrito para as ações que necessitam do certificate_pkcs12 para assinatura

Returns:

  • (Boolean)


26
27
28
# File 'lib/br_nfe/base.rb', line 26

def certificado_obrigatorio?
	false
end

#certificateObject



227
228
229
# File 'lib/br_nfe/base.rb', line 227

def certificate
	@certificate ||= certificate_pkcs12.try :certificate
end

#certificate=(value) ⇒ Object



223
224
225
# File 'lib/br_nfe/base.rb', line 223

def certificate=(value)
	@certificate = value
end

#certificate_keyObject



231
232
233
# File 'lib/br_nfe/base.rb', line 231

def certificate_key
	@certificate_key ||= certificate_pkcs12.try :key
end

#certificate_key=(value) ⇒ Object



235
236
237
# File 'lib/br_nfe/base.rb', line 235

def certificate_key=(value)
	@certificate_key = value
end

#certificate_pkcs12Object



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
# File 'lib/br_nfe/base.rb', line 201

def certificate_pkcs12
	return @certificate_pkcs12 if @certificate_pkcs12
	@certificate_pkcs12 = nil
	
	# É utilizado uma Thread e limpado os errors do OpenSSL para evitar perda de 
	# conexão com o banco de dados PostgreSQL.
	# Veja: http://stackoverflow.com/questions/33112155/pgconnectionbad-pqconsumeinput-ssl-error-key-values-mismatch/36283315#36283315
	# Veja: https://github.com/tedconf/front_end_builds/pull/66
	Thread.new do 
		@certificate_pkcs12 = OpenSSL::PKCS12.new(certificate_pkcs12_value, certificate_pkcs12_password) 
		OpenSSL.errors.clear
	end.join
	OpenSSL.errors.clear

	@certificate_pkcs12 
rescue
end

#certificate_pkcs12=(value) ⇒ Object



219
220
221
# File 'lib/br_nfe/base.rb', line 219

def certificate_pkcs12=(value)
	@certificate_pkcs12 = value
end

#client_wsdlObject

Cliente WSDL utilizado para fazer a requisição. Utilizando a gem savon. Veja mais detalhes em savonrb.com/version2/client.html



180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/br_nfe/base.rb', line 180

def client_wsdl
	@client_wsdl ||= Savon.client do |global|
		global.wsdl             wsdl
		global.log              BrNfe.client_wsdl_log
		global.pretty_print_xml BrNfe.client_wsdl_pretty_print_xml
		global.ssl_verify_mode  :none
		if ssl_request?
			global.ssl_version           ssl_version
			global.ssl_cert              certificate
			global.ssl_cert_key          certificate_key
			global.ssl_cert_key_password certificate_pkcs12_password
		end
	end
end

#content_xmlObject

Esse método serve para ser utilizado no Base de cada orgão emissor onde em alguns casos é necessário colocar o xml em um CDATA É esse método que é passado dentro do Body da equisição SOAP



86
87
88
# File 'lib/br_nfe/base.rb', line 86

def content_xml
	xml_builder
end

#env_namespaceObject

Namespace da requisição SOAP



52
53
54
# File 'lib/br_nfe/base.rb', line 52

def env_namespace
	:soapenv
end

#env_test?Boolean

Returns:

  • (Boolean)


38
39
40
# File 'lib/br_nfe/base.rb', line 38

def env_test?
	env == :test
end

#find_xml(file_name, dir, context = nil, options = {}) ⇒ Object



274
275
276
277
278
# File 'lib/br_nfe/base.rb', line 274

def find_xml(file_name, dir, context=nil, options={})
	if File.exists?("#{dir}/#{file_name}.xml.slim")
		Slim::Template.new("#{dir}/#{file_name}.xml.slim").render(context, options).html_safe 
	end
end

#get_xml_dirs(custom_dir_path = nil) ⇒ Object



280
281
282
# File 'lib/br_nfe/base.rb', line 280

def get_xml_dirs(custom_dir_path=nil)
	[custom_dir_path, xml_current_dir_path, xml_default_dir_path].flatten.select(&:present?)
end

#id_attribute?Boolean

Para saber se deve add o attr id na assinatura

Returns:

  • (Boolean)


57
58
59
# File 'lib/br_nfe/base.rb', line 57

def id_attribute?
	true
end

#message_namespacesObject



124
125
126
# File 'lib/br_nfe/base.rb', line 124

def message_namespaces
	{}
end

#method_wsdlObject

Método que contem qual a operação que deverá ser chamada do WS SOAP.



70
71
72
# File 'lib/br_nfe/base.rb', line 70

def method_wsdl
	raise "Não implementado."
end

#namespace_for_signatureObject

Utilizado para colocar o namespace nas tags da assiantura Exemplo: <ns2:Signature Id=“?”>

<ns2:SignedInfo Id="?">
  <ns2:CanonicalizationMethod Algorithm="?">?</ns2:CanonicalizationMethod>
  .....


121
122
# File 'lib/br_nfe/base.rb', line 121

def namespace_for_signature
end

#namespace_for_tagsObject

Utilizado para colocar o namespace nas tags de valores Exemplo: <ns1:LoteRps id=“123”>

<ns1:NumeroLote>3311</ns1:NumeroLote>
<ns1:Cnpj>23020443000140</ns1:Cnpj>


111
112
# File 'lib/br_nfe/base.rb', line 111

def namespace_for_tags
end

#namespace_identifierObject

O Namespace Indentifier é utilizado para adicionar o namespace na tag principal da requisição. Normalmente deve seguir o namespace utilizado para identificar o namespace da mensagem.

Exemplo: se o método message_namespaces for BrNfe::Base.xmlns:ns1=“httpxmlns:ns1=“http.…” então o namespace_identifier deveria ser ‘ns1:’. E com isso irá adicionar o namespace na tag principal da requsição. Exemplo com a requisição EnviarLoteRps: COM namespace_identifier => ns1:EnviarLoteRpsEnvio SEM namespace_identifier => EnviarLoteRpsEnvio

Tipo de retorno: String OR Nil



103
104
# File 'lib/br_nfe/base.rb', line 103

def namespace_identifier
end

#original_responseObject



42
43
44
# File 'lib/br_nfe/base.rb', line 42

def original_response
	@original_response
end

#render_xml(file_name, opts = {}) ⇒ Object

Renderiza o xml a partir do nome de um arquivo Irá procurar o arquivo a partir dos seguintes diretórios> 1° - A partir do parâmetro :dir_path 2° - A partir do método xml_current_dir_path 3° - A partir do método xml_default_dir_path

Se não encontrar o arquivo em nenhum dos diretórios irá execurar uma excessão de RuntimeError

Utilização ‘render_xml(’file_name’, ‘/my/custom/dir’, context: Object‘

<b>Tipo de retorno: <b> String (XML)



253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/br_nfe/base.rb', line 253

def render_xml file_name, opts={}
	opts ||= {}
	default_options = opts.extract!(:dir_path, :context)
	default_options[:context] ||= self
	
	# Inicializa a variavel xml com nil para comparar se oa rquivo foi de fato encontrado.
	xml = nil
	get_xml_dirs(default_options[:dir_path]).each do |dir|
		if xml = find_xml(file_name, dir, default_options[:context], opts)
			break # Stop loop
		end
	end

	# Lança uma excessão se não for encontrado o xml
	# Deve verificar se é nil pois o arquivo xml pode estar vazio
	if xml.nil?
		raise "Arquivo #{file_name}.xml.slim não encontrado nos diretórios #{get_xml_dirs(default_options[:dir_path])}" 
	end
	xml
end

#responseObject



46
47
48
# File 'lib/br_nfe/base.rb', line 46

def response
	@response
end

#response_encodingObject



141
142
143
# File 'lib/br_nfe/base.rb', line 141

def response_encoding
	"UTF-8"
end

#sign_xml(xml, sign_nodes = []) ⇒ Object

USE EXAMPLE

@xml = <?xml version="1.0" encoding="ISO-8859-1"?>
        <EnviarLoteRpsEnvio xmlns="http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd">
          <LoteRps id="L2">
            ...
            <ListaRps>
              <Rps>
                <InfRps id="R2">
                  ...
                </>InfRps
              </Rps>
              <Rps>
                <InfRps id="R3">
                  ...
                </>InfRps
              </Rps>
            </ListaRps>
          </LoteRps>
        </EnviarLoteRpsEnvio>

sign_nodes = [

{

node_path: “//nf:EnviarLoteRpsEnvio/nf:LoteRps/nf:ListaRps/nf:Rps/nf:InfRps”, node_namespaces: ‘www.abrasf.org.br/ABRASF/arquivos/nfse.xsd’, node_ids: [‘R2’,‘R3’]

},
{
  node_path: "//nf:EnviarLoteRpsEnvio/nf:LoteRps", 
  node_namespaces: {nf: 'http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd'},
  node_ids: ['L2']
},

]

Call Method: sign_xml(@xml, sign_nodes)



352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
# File 'lib/br_nfe/base.rb', line 352

def sign_xml(xml, sign_nodes=[])
	return xml unless certificate
	signer = Signer.new(xml)
	signer.cert        = certificate
	signer.private_key = certificate_key

	# Como o documento não é um envelope SOAP preciso setar o security_node e o security_token_id
	signer.security_node = signer.document.root
	signer.security_token_id = ""

	sign_nodes.each do |options|
		node_ids = [options[:node_ids]].flatten
		signer.document.xpath(options[:node_path], options[:node_namespaces]).each_with_index do |node, i|
			# digo quais tags devem ser assinadas
			signer.digest!(node, id: "#{node_ids[i]}", enveloped: true)
		end				
	end
	
	# Assina o XML
	signer.sign!(security_token: false, issuer_serial: true)

	signer.to_xml
end

#signature_typeObject

Existem 2 tipos de assinatura da NFS-e

  • :default

    Assina o XML no momento em que está sendo montado. Funciona normalmente para a maiora das prefeituras. Primeiro assina cada RPS individualmente e adiciona a tag da assinatura e depois Assina o LOTE RPS com todas os RPSs assinados

  • :method_sign

    Assina o XML após a montagem do mesmo. Utiliza a gem ‘signer’ para assinar os nós do XML. Adiciona toda a assinatura no final do XML, diferente do que é descrito nas documentações. Porém em algumas cidades só consegui validar a assinatura utilizando esse método Estava dando o erro: E515 - Erro ao validar assinatura. - Remessa adulterada após a assinatura.



310
311
312
# File 'lib/br_nfe/base.rb', line 310

def signature_type
	:default
end

#signature_type?(type) ⇒ Boolean

Returns:

  • (Boolean)


313
314
315
# File 'lib/br_nfe/base.rb', line 313

def signature_type?(type)
	signature_type == type
end

#soap_namespacesObject



128
129
130
131
132
133
134
135
# File 'lib/br_nfe/base.rb', line 128

def soap_namespaces
	{
		'xmlns:soapenv' => 'http://schemas.xmlsoap.org/soap/envelope/',
		'xmlns:ins0'    => 'http://www.w3.org/2000/09/xmldsig#',
		'xmlns:xsd'     => 'http://www.w3.org/2001/XMLSchema',
		'xmlns:xsi'     => 'http://www.w3.org/2001/XMLSchema-instance'
	}
end

#soap_xmlObject

XML que irá na requisição SOAP

Tipo de retorno: _String XML_



157
158
159
# File 'lib/br_nfe/base.rb', line 157

def soap_xml
	@soap_xml ||= "#{tag_xml}#{render_xml('soap_env')}".html_safe
end

#ssl_request?Boolean

Returns:

  • (Boolean)


30
31
32
# File 'lib/br_nfe/base.rb', line 30

def ssl_request?
	false
end

#ssl_versionObject

Versão da requisição SSL caso o servidor necessite de autenticação SSL Valores possíveis: [:TLSv1_2, :TLSv1_1, :TLSv1, :SSLv3, :SSLv23] Default: :SSLv3



173
174
175
# File 'lib/br_nfe/base.rb', line 173

def ssl_version
	:SSLv3
end

#tag_xmlObject

Tag XML que vai na requisição SOAP

Tipo de retorno: String



149
150
151
# File 'lib/br_nfe/base.rb', line 149

def tag_xml
	"<?xml version=\"1.0\" encoding=\"#{wsdl_encoding}\"?>"
end

#wsdlObject

Deve conter o LINK do webservice a ser chamado



63
64
65
# File 'lib/br_nfe/base.rb', line 63

def wsdl
	raise "Não implementado."
end

#wsdl_encodingObject



137
138
139
# File 'lib/br_nfe/base.rb', line 137

def wsdl_encoding
	"UTF-8"
end

#xml_builderObject

O xml_builder é o que contém o conteúdo de cada tipo de requisição e deve ser sobrescrito em cada classe implementada. Por exemplo: recepcao_lote_rps, consulta_lote_rps, cancelamento_nfs, etc..



78
79
80
# File 'lib/br_nfe/base.rb', line 78

def xml_builder
	raise "Não implementado."
end

#xml_current_dir_pathObject

Diretório personalizado para cada classe Podendo ser sobrescrito em cada herança



287
288
289
# File 'lib/br_nfe/base.rb', line 287

def xml_current_dir_path
	[]
end

#xml_default_dir_pathObject

Diretório padrão dos arquivos XML



293
294
295
# File 'lib/br_nfe/base.rb', line 293

def xml_default_dir_path
	"#{BrNfe.root}/lib/br_nfe/xml"
end

#xml_versionObject

Versão do XML utilizado Cada Cidade pode utilizar uma versão diferente do XML

Tipo de retorno: Symbol



166
167
168
# File 'lib/br_nfe/base.rb', line 166

def xml_version
	:v1
end