Created
February 1, 2014 18:49
-
-
Save marcelcaraciolo/8756769 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- 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