Skip to content

Instantly share code, notes, and snippets.

@marcelcaraciolo
Created February 1, 2014 18:49
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save marcelcaraciolo/8756769 to your computer and use it in GitHub Desktop.
Save marcelcaraciolo/8756769 to your computer and use it in GitHub Desktop.
# -*- coding: utf-8 -*-
from xml.dom import minidom
from core.utils import asciize
from signin import sign_file
import urllib2
import os, decimal
import settings
from nfe.exceptions import NoContratorOrIncompleteInformation
from nfe.utils import dict2XML
class NFEXMLCreator():
PRIVATE_RESOURCES_PATH = os.path.join(settings.PROJECT_ROOT, '../private_resources/%s')
OUTPUT_PATH = os.path.join(settings.PROJECT_ROOT, '../private_resources/output/%s')
XMLNS = 'http://www.abrasf.org.br/ABRASF/arquivos/nfse.xsd'
ALL = 0
INFO_RPS = 1
ENVIARLOTERPSENVIO = 2
RPS = 3
PRIVATE_KEY = PRIVATE_RESOURCES_PATH % 'ca.key'
X509_CERTIFICATE = PRIVATE_RESOURCES_PATH % 'cert.cer'
def _get_contractor(self):
try:
from nfe.models import ServiceContractor, InformacoesNotaFiscal
contractor = ServiceContractor.objects.get()
# Check whether has the attribute trying to access it, otherwise raise an exception
contractor.informacoes_nota_fiscal
return contractor
except (InformacoesNotaFiscal.DoesNotExist, ServiceContractor.DoesNotExist):
raise NoContratorOrIncompleteInformation
def _create_envelope(self, contractor, notas_fiscais, xml_filepath):
lote_xml = {
'EnviarLoteRpsEnvio': ({'xmlns': self.__class__.XMLNS}, {
'LoteRps': ({'Id': 'L1'}, {
'1__NumeroLote': '1',
'2__Cnpj': contractor.cnpj,
'3__InscricaoMunicipal': contractor.inscricao_municipal,
'4__QuantidadeRps': len(notas_fiscais),
'5__ListaRps': {
'Rps': [],
},
}),
})
}
for (count, nota_fiscal) in enumerate(notas_fiscais):
count += 1
order_total = max(nota_fiscal.order.total
- (nota_fiscal.order.discount or 0)
+ (nota_fiscal.order.shipping_cost or 0),
decimal.Decimal('0.00')
)
storeprofile = nota_fiscal.order.contact.storeprofile
informacoes_nota_fiscal = contractor.informacoes_nota_fiscal
######## TESTE ########
order_total = decimal.Decimal('1.50')
import datetime
#######################
nota_xml = {
'InfRps': ({'Id': 'R%d' % count}, {
'1__IdentificacaoRps': {
'1__Numero': count,
'2__Serie': informacoes_nota_fiscal.serie,
'3__Tipo': informacoes_nota_fiscal.tipo,
},
# '2__DataEmissao':
# nota_fiscal.creation_date.strftime('%Y-%m-%dT%H:%M:%S'),
######## TESTE ########
'2__DataEmissao':
datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%S'),
#######################
'3__NaturezaOperacao': informacoes_nota_fiscal.natureza_operacao,
'4__OptanteSimplesNacional':
informacoes_nota_fiscal.optante_simples_nacional,
'5__IncentivadorCultural':
informacoes_nota_fiscal.incentivador_cultural,
'6__Status': '1',
'7__Servico': {
'1__Valores': {
'1__ValorServicos': '%.2f' % order_total,
'2__ValorDeducoes': '0',
'3__ValorPis': '0',
'4__ValorCofins': '0',
'5__ValorInss': '0',
'6__ValorIr': '0',
'7__ValorCsll': '0',
# TODO: Valor provisório.
'8__IssRetido': '2',
'9__ValorIss':
'%.2f' % (informacoes_nota_fiscal.aliquota * order_total),
'10__OutrasRetencoes': '0',
'11__Aliquota': '%.2f' % informacoes_nota_fiscal.aliquota,
'12__DescontoIncondicionado': '0.0',
'13__DescontoCondicionado': '0.0',
},
'2__ItemListaServico': informacoes_nota_fiscal.item_lista_servico,
'3__CodigoCnae': informacoes_nota_fiscal.codigo_cnae,
'4__CodigoTributacaoMunicipio':
informacoes_nota_fiscal.codigo_tributacao_municipio,
# '5__Discriminacao': nota_fiscal.discriminacao(),
######## TESTE ########
'5__Discriminacao': 'teste',
#######################
'6__CodigoMunicipio': informacoes_nota_fiscal.codigo_municipio,
},
'8__Prestador': {
'1__Cnpj': contractor.cnpj,
'2__InscricaoMunicipal': contractor.inscricao_municipal,
},
'9__Tomador': {
'1__IdentificacaoTomador': {
'CpfCnpj': {
# 'Cpf': storeprofile.cpf,
######## TESTE ########
'Cpf': '08927640403',
#######################
},
},
# '2__RazaoSocial': storeprofile.fullname,
# '3__Endereco': {
# '1__Endereco': asciize(storeprofile.address),
# '2__Numero': storeprofile.number,
# '3__Complemento': storeprofile.complement,
# '4__Bairro': storeprofile.district,
# '5__CodigoMunicipio': nota_fiscal.city.code,
# '6__Uf': storeprofile.state.abbr.upper(),
# '7__Cep': storeprofile.zip_code,
######## TESTE ########
'2__RazaoSocial': 'Lucas Inojosa Costa Ferreira',
'3__Endereco': {
'1__Endereco': u'Rua Prof. Mário de Castro',
'2__Numero': 192,
'3__Complemento': 1402,
'4__Bairro': 'Boa Viagem',
'5__CodigoMunicipio': '2611606',
'6__Uf': 'PE',
'7__Cep': '51030260',
},
#######################
},
})
}
((lote_xml['EnviarLoteRpsEnvio'][1]
)['LoteRps'][1]['5__ListaRps']['Rps']
).append(nota_xml)
xml = dict2XML(lote_xml, indent=True, utf8=True)
xml_file = open(xml_filepath, 'w')
xml_file.write(xml)
xml_file.close()
def _sign_xml(self, typeN, xml_file, signed_xml_file, signed_xml_temp_file):
#Retira a chave privada ligada ao certificado
signed_file = open(signed_xml_file, 'w')
(key, cert) = (self.__class__.PRIVATE_KEY, self.__class__.X509_CERTIFICATE)
if typeN != self.__class__.ALL:
node = ('EnviarLoteRpsEnvio'
if typeN == self.__class__.ENVIARLOTERPSENVIO else
'Rps'
if typeN == self.__class__.RPS else
'InfRps'
if typeN == self.__class__.INFO_RPS else
None
)
sign_file(xml_file, key, cert, node, signed_file)
signed_file.close()
else:
signed_file.close()
signed_temp_file = open(signed_xml_temp_file, 'w')
sign_file(xml_file, key, cert, 'EnviarLoteRpsEnvio', signed_temp_file)
signed_temp_file.close()
signed_file = open(signed_xml_file, 'w')
sign_file(signed_xml_temp_file, key, cert, 'Rps', signed_file)
signed_file.close()
# os.remove(signed_xml_temp_file)
# os.remove(xml_file)
def create_notas_xml(self, notas_fiscais, xml_filename):
contractor = self._get_contractor()
xml_filepath = self.__class__.OUTPUT_PATH % xml_filename
xml_signed_filepath = (self.__class__.OUTPUT_PATH % 'signed_%s' % xml_filename)
xml_signed_temp_filepath = (self.__class__.OUTPUT_PATH %
'signed_temp_%s' % xml_filename)
self._create_envelope(contractor, notas_fiscais, xml_filepath)
self._sign_xml(self.__class__.ALL,
xml_filepath, xml_signed_filepath, xml_signed_temp_filepath
)
def create_xml_consultar_situacao_lote_rps(self):
contractor = self._get_contractor()
xml_dict = {
'ConsultarSituacaoLoteRpsEnvio': ({'xmlns': self.__class__.XMLNS}, {
'1__Prestador': {
'1__Cnpj': contractor.cnpj,
'2__InscricaoMunicipal': contractor.inscricao_municipal,
},
# TODO: Valor provisório
'2__Protocolo': '1000',
})
}
return dict2XML(xml_dict, indent=False, utf8=True)
def create_xml_consultar_nota(self, start_date, end_date, cpf_or_cnpj, is_cpf):
contractor = self._get_contractor()
xml_dict = {
'ConsultarNfseEnvio': ({'xmlns': self.__class__.XMLNS}, {
'1__Prestador': {
'1__Cnpj': contractor.cnpj,
'2__InscricaoMunicipal': contractor.inscricao_municipal,
},
'2__PeriodoEmissao': {
'1__DataInicial': start_date.strftime('%Y-%m-%d'),
'2__DataFinal': end_date.strftime('%Y-%m-%d'),
},
'3__Tomador': {
'CpfCnpj': {
('Cpf' if is_cpf else 'Cnpj'): cpf_or_cnpj
}
}
})
}
return dict2XML(xml_dict, indent=False, utf8=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment