def _construir_xml_status_pr(self, cabecalho, metodo, dados): u"""Mota o XML para o envio via SOAP""" raiz = etree.Element('{%s}Envelope' % NAMESPACE_SOAP, nsmap={ 'xsi': NAMESPACE_XSI, 'xsd': NAMESPACE_XSD, 'soap': NAMESPACE_SOAP }) c = etree.SubElement(raiz, '{%s}Header' % NAMESPACE_SOAP) c.append(cabecalho) body = etree.SubElement(raiz, '{%s}Body' % NAMESPACE_SOAP) a = etree.SubElement(body, 'nfeDadosMsg', xmlns=NAMESPACE_METODO + metodo) a.append(dados) return raiz
def status_servico(self, modelo): """ Verifica status do servidor da receita. :param modelo: modelo é a string com tipo de serviço que deseja consultar, Ex: nfe ou nfce :return: """ url = self._get_url(modelo, 'STATUS') # Monta XML do corpo da requisição raiz = etree.Element('consStatServ', versao=VERSAO_PADRAO, xmlns=NAMESPACE_NFE) etree.SubElement(raiz, 'tpAmb').text = str(self._ambiente) etree.SubElement(raiz, 'cUF').text = CODIGOS_ESTADOS[self.uf.upper()] etree.SubElement(raiz, 'xServ').text = 'STATUS' xml = self._construir_xml_soap('NFeStatusServico4', raiz) return self._post(url, xml)
def _serializar_transportadora(self, transportadora, tag_raiz='transporta', retorna_string=True): raiz = etree.Element(tag_raiz) # Dados da transportadora etree.SubElement(raiz, transportadora.tipo_documento).text = so_numeros( transportadora.numero_documento) etree.SubElement(raiz, 'xNome').text = transportadora.razao_social etree.SubElement(raiz, 'IE').text = transportadora.inscricao_estadual # Endereço etree.SubElement(raiz, 'xEnder').text = transportadora.endereco_logradouro etree.SubElement(raiz, 'cMun').text = transportadora.endereco_municipio etree.SubElement(raiz, 'xMun').text = obter_municipio_por_codigo( transportadora.endereco_municipio, transportadora.endereco_uf, ) etree.SubElement(raiz, 'UF').text = transportadora.endereco_uf if retorna_string: return etree.tostring(raiz, pretty_print=True) else: return raiz
def consulta_nota(self, modelo, chave): """ Este método oferece a consulta da situação da NF-e/NFC-e na Base de Dados do Portal da Secretaria de Fazenda Estadual. :param modelo: Modelo da nota :param chave: Chave da nota :return: """ # url do serviço url = self._get_url(modelo=modelo, consulta='CHAVE') # Monta XML do corpo da requisição raiz = etree.Element('consSitNFe', versao=VERSAO_PADRAO, xmlns=NAMESPACE_NFE) etree.SubElement(raiz, 'tpAmb').text = str(self._ambiente) etree.SubElement(raiz, 'xServ').text = 'CONSULTAR' etree.SubElement(raiz, 'chNFe').text = chave # Monta XML para envio da requisição xml = self._construir_xml_soap('NFeConsultaProtocolo4', raiz) return self._post(url, xml)
def consulta_recibo(self, modelo, numero): """ Este método oferece a consulta do resultado do processamento de um lote de NF-e. O aplicativo do Contribuinte deve ser construído de forma a aguardar um tempo mínimo de 15 segundos entre o envio do Lote de NF-e para processamento e a consulta do resultado deste processamento, evitando a obtenção desnecessária do status de erro 105 - "Lote em Processamento". """ # url do serviço url = self._get_url(modelo=modelo, consulta='RECIBO') # Monta XML do corpo da requisição raiz = etree.Element('consReciNFe', versao=VERSAO_PADRAO, xmlns=NAMESPACE_NFE) etree.SubElement(raiz, 'tpAmb').text = str(self._ambiente) etree.SubElement(raiz, 'nRec').text = numero # Monta XML para envio da requisição xml = self._construir_xml_status_pr(cabecalho=self._cabecalho_soap(metodo='NfeRetAutorizacao'), metodo='NfeRetAutorizacao', dados=raiz) return self._post(url, xml)
def cancelar(self, modelo, evento, idlote=1): """ Envia um evento de cancelamento de nota fiscal """ # url do serviço url = self._get_url(modelo=modelo, consulta='EVENTOS') # Monta XML do corpo da requisição raiz = etree.Element('envEvento', versao='1.00', xmlns=NAMESPACE_NFE) etree.SubElement(raiz, 'idLote').text = str(idlote) # numero autoincremental gerado pelo sistema raiz.append(evento) xml = self._construir_xml_status_pr(cabecalho=self._cabecalho_soap(metodo='RecepcaoEvento'), metodo='RecepcaoEvento', dados=raiz) return self._post(url, xml)
def nfeInutilizacaoNF(self, raiz): data_hora = datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%S') ret = etree.Element('retInutNFe') etree.SubElement(ret, 'versao').text = '1.00' # FIXME xml_dados = raiz.getroot().getchildren()[0].getchildren()[0].getchildren()[1].text xml = etree.tostring(ret, encoding='utf-8', xml_declaration=True) self.write(xml)
def consulta_distribuicao(self, cnpj=None, cpf=None, chave=None, nsu=0, consulta_nsu=False): """ O XML do pedido de distribuição suporta três tipos de consultas que são definidas de acordo com a tag informada no XML. As tags são distNSU, consNSU e consChNFe. a) distNSU – Distribuição de Conjunto de DF-e a Partir do NSU Informado b) consNSU – Consulta DF-e Vinculado ao NSU Informado c) consChNFe – Consulta de NF-e por Chave de Acesso Informada :param cnpj: CNPJ do interessado :param cpf: CPF do interessado :param chave: Chave da NF-e a ser consultada :param nsu: Ultimo nsu ou nsu específico para ser consultado. :return: """ # url url = self._get_url_an(consulta='DISTRIBUICAO') # Monta XML para envio da requisição raiz = etree.Element('distDFeInt', versao='1.01', xmlns=NAMESPACE_NFE) etree.SubElement(raiz, 'tpAmb').text = str(self._ambiente) if self.uf: etree.SubElement( raiz, 'cUFAutor').text = CODIGOS_ESTADOS[self.uf.upper()] if cnpj: etree.SubElement(raiz, 'CNPJ').text = cnpj else: etree.SubElement(raiz, 'CPF').text = cpf if not chave and not consulta_nsu: distNSU = etree.SubElement(raiz, 'distNSU') etree.SubElement(distNSU, 'ultNSU').text = str(nsu).zfill(15) if chave: consChNFe = etree.SubElement(raiz, 'consChNFe') etree.SubElement(consChNFe, 'chNFe').text = chave if consulta_nsu: nsu_tag = etree.SubElement(raiz, 'consNSU') etree.SubElement(nsu_tag, 'NSU').text = nsu #Monta XML para envio da requisição xml = self._construir_xml_soap('NFeDistribuicaoDFe', raiz) return self._post(url, xml)
def nfeStatusServicoNF2(self, raiz): data_hora = datetime.datetime.now().strftime('%Y-%m-%dT%H:%M:%S') ret = etree.Element('retConsStatServ') etree.SubElement(ret, 'versao').text = '1.00' # FIXME etree.SubElement(ret, 'tbAmb').text = '2' # Homologação etree.SubElement(ret, 'verAplic').text = self.sigla_servidor etree.SubElement(ret, 'cStat').text = '1' # FIXME etree.SubElement( ret, 'xMotivo').text = 'Servico em funcionamento normal' # FIXME etree.SubElement(ret, 'cUF').text = CODIGOS_ESTADOS[self.sigla_servidor] etree.SubElement(ret, 'dhRecbto').text = data_hora etree.SubElement(ret, 'tMed').text = '10' etree.SubElement(ret, 'dhRetorno').text = data_hora etree.SubElement(ret, 'xObs').text = 'Nenhuma informacao adicional' xml = etree.tostring(ret, encoding='utf-8', xml_declaration=True) self.write(xml)
def download(self, cnpj, chave): """ Metodo para download de NFe por parte de destinatário. O certificado digital deve ser o mesmo do destinatário da Nfe. NT 2012/002 """ # url do serviço url = self._get_url_AN(consulta='DOWNLOAD') # Monta XML do corpo da requisição raiz = etree.Element('downloadNFe', versao='1.00', xmlns=NAMESPACE_NFE) etree.SubElement(raiz, 'tpAmb').text = str(self._ambiente) etree.SubElement(raiz, 'xServ').text = 'DOWNLOAD NFE' etree.SubElement(raiz, 'CNPJ').text = str(cnpj) etree.SubElement(raiz, 'chNFe').text = str(chave) # Monta XML para envio da requisição xml = self._construir_xml_soap('NfeDownloadNF', raiz) return self._post(url, xml)
def status_servico(self, modelo): """ Verifica status do servidor da receita. """ """ modelo é a string com tipo de serviço que deseja consultar Ex: nfe ou nfce """ url = self._get_url(modelo=modelo, consulta='STATUS') # Monta XML do corpo da requisição raiz = etree.Element('consStatServ', versao=VERSAO_PADRAO, xmlns=NAMESPACE_NFE) etree.SubElement(raiz, 'tpAmb').text = str(self._ambiente) etree.SubElement(raiz, 'cUF').text = CODIGOS_ESTADOS[self.uf.upper()] etree.SubElement(raiz, 'xServ').text = 'STATUS' # Monta XML para envio da requisição xml = self._construir_xml_status_pr( cabecalho=self._cabecalho_soap(metodo='NfeStatusServico2'), metodo='NfeStatusServico2', dados=raiz) # Chama método que efetua a requisição POST no servidor SOAP return self._post(url, xml)
def _construir_xml_soap(self, metodo, dados, cabecalho=False): """Mota o XML para o envio via SOAP""" raiz = etree.Element('{%s}Envelope' % NAMESPACE_SOAP, nsmap={ 'xsi': NAMESPACE_XSI, 'xsd': NAMESPACE_XSD, 'soap': NAMESPACE_SOAP }) body = etree.SubElement(raiz, '{%s}Body' % NAMESPACE_SOAP) ## distribuição tem um corpo de xml diferente if metodo == 'NFeDistribuicaoDFe': x = etree.SubElement(body, 'nfeDistDFeInteresse', xmlns=NAMESPACE_METODO + metodo) a = etree.SubElement(x, 'nfeDadosMsg') else: a = etree.SubElement(body, 'nfeDadosMsg', xmlns=NAMESPACE_METODO + metodo) a.append(dados) return raiz
def consulta_notas_cnpj(self, cnpj, nsu=0): """ “Serviço de Consulta da Relação de Documentos Destinados” para um determinado CNPJ de destinatário informado na NF-e. """ # url do serviço url = self._get_url(modelo='nfe', consulta='DESTINADAS') # Monta XML do corpo da requisição raiz = etree.Element('consNFeDest', versao='1.01', xmlns=NAMESPACE_NFE) etree.SubElement(raiz, 'tpAmb').text = str(self._ambiente) etree.SubElement(raiz, 'xServ').text = 'CONSULTAR NFE DEST' etree.SubElement(raiz, 'CNPJ').text = cnpj # Indicador de NF-e consultada: # 0=Todas as NF-e; # 1=Somente as NF-e que ainda não tiveram manifestação do destinatário (Desconhecimento da operação, Operação não Realizada ou Confirmação da Operação); # 2=Idem anterior, incluindo as NF-e que também não tiveram a Ciência da Operação. etree.SubElement(raiz, 'indNFe').text = '0' # Indicador do Emissor da NF-e: # 0=Todos os Emitentes / Remetentes; # 1=Somente as NF-e emitidas por emissores / remetentes que não tenham o mesmo CNPJ-Base do destinatário (para excluir as notas fiscais de transferência entre filiais). etree.SubElement(raiz, 'indEmi').text = '0' # Último NSU recebido pela Empresa. Caso seja informado com zero, ou com um NSU muito antigo, a consulta retornará unicamente as notas fiscais que tenham sido recepcionadas nos últimos 15 dias. etree.SubElement(raiz, 'ultNSU').text = str(nsu) # Monta XML para envio da requisição xml = self._construir_xml_status_pr( cabecalho=self._cabecalho_soap(metodo='NfeConsultaDest'), metodo='NfeConsultaDest', dados=raiz) return self._post(url, xml)
def consultar_cadastro(self, modelo, ie, cnpj): # RS implementa um método diferente na consulta de cadastro if self.uf.upper() == 'RS': url = NFE['RS']['CADASTRO'] elif self.uf.upper() == 'SVRS': url = NFE['SVRS']['CADASTRO'] elif self.uf.upper() == 'SVC-RS': url = NFE['SVC-RS']['CADASTRO'] else: url = self._get_url(modelo=modelo, consulta='CADASTRO') raiz = etree.Element('ConsCad', versao=VERSAO_PADRAO, xmlns=NAMESPACE_NFE) info = etree.SubElement(raiz, 'infCons') etree.SubElement(info, 'xServ').text = 'CONS-CAD' etree.SubElement(info, 'UF').text = self.uf.upper() etree.SubElement(info, 'IE').text = ie etree.SubElement(info, 'CNPJ').text = cnpj #etree.SubElement(info, 'CPF').text = cpf # Monta XML para envio da requisição xml = self._construir_xml_status_pr(cabecalho=self._cabecalho_soap(metodo='CadConsultaCadastro2'), metodo='CadConsultaCadastro2', dados=raiz) # Chama método que efetua a requisição POST no servidor SOAP return self._post(url, xml)
def consulta_cadastro(self, modelo, cnpj): # UF que utilizam a SVRS - Sefaz Virtual do RS: Para serviço de Consulta Cadastro: AC, RN, PB, SC lista_svrs = ['AC', 'RN', 'PB', 'SC'] # RS implementa um método diferente na consulta de cadastro if self.uf.upper() == 'RS': url = NFE['RS']['CADASTRO'] elif self.uf.upper() in lista_svrs: url = NFE['SVRS']['CADASTRO'] elif self.uf.upper() == 'SVC-RS': url = NFE['SVC-RS']['CADASTRO'] else: url = self._get_url(modelo=modelo, consulta='CADASTRO') raiz = etree.Element('ConsCad', versao='2.00', xmlns=NAMESPACE_NFE) info = etree.SubElement(raiz, 'infCons') etree.SubElement(info, 'xServ').text = 'CONS-CAD' etree.SubElement(info, 'UF').text = self.uf.upper() etree.SubElement(info, 'CNPJ').text = cnpj #etree.SubElement(info, 'CPF').text = cpf # Monta XML para envio da requisição xml = self._construir_xml_soap('CadConsultaCadastro4', raiz) # Chama método que efetua a requisição POST no servidor SOAP return self._post(url, xml)
def _cabecalho(self, retorna_string=True): """ Monta o XML do cabeçalho da requisição wsdl Namespaces padrão homologação (Ginfes) """ xml_declaration='<?xml version="1.0" encoding="UTF-8"?>' # cabecalho = '<ns2:cabecalho versao="3" xmlns:ns2="http://www.ginfes.com.br/cabecalho_v03.xsd" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><versaoDados>3</versaoDados></ns2:cabecalho>' # cabecalho raiz = etree.Element('{%s}cabecalho'%self._namespace, nsmap={'ns2':self._namespace, 'xsi':NAMESPACE_XSI}, versao=self._versao) etree.SubElement(raiz, 'versaoDados').text = self._versao if retorna_string: cabecalho = etree.tostring(raiz, encoding='unicode', pretty_print=False).replace('\n','') cabecalho = xml_declaration + cabecalho return cabecalho else: return raiz
def _cabecalho2(self, retorna_string=True): """ Monta o XML do cabeçalho da requisição wsdl Namespaces que funcionaram em produção (Ginfes)""" xml_declaration = '<?xml version="1.0" encoding="UTF-8"?>' # cabecalho raiz = etree.Element('cabecalho', xmlns=self._namespace, versao=self._versao) etree.SubElement(raiz, 'versaoDados').text = self._versao if retorna_string: cabecalho = etree.tostring(raiz, encoding='unicode', pretty_print=False).replace('\n', '') cabecalho = xml_declaration + cabecalho return cabecalho else: return raiz
def evento(self, modelo, evento, idlote=1): """ Envia um evento de nota fiscal (cancelamento e carta de correção)""" # url do serviço try: # manifestacao url é do AN if evento[0][5].text.startswith('2'): url = self._get_url_AN(consulta='EVENTOS') else: url = self._get_url(modelo=modelo, consulta='EVENTOS') except Exception: url = self._get_url(modelo=modelo, consulta='EVENTOS') # Monta XML do corpo da requisição raiz = etree.Element('envEvento', versao='1.00', xmlns=NAMESPACE_NFE) etree.SubElement(raiz, 'idLote').text = str( idlote) # numero autoincremental gerado pelo sistema raiz.append(evento) xml = self._construir_xml_soap('NFeRecepcaoEvento4', raiz) return self._post(url, xml)
def _serializar_entrega_retirada(self, entrega_retirada, tag_raiz='entrega', retorna_string=True): raiz = etree.Element(tag_raiz) # Dados da entrega/retirada etree.SubElement(raiz, entrega_retirada.tipo_documento).text = so_numeros(entrega_retirada.numero_documento) # Endereço etree.SubElement(raiz, 'xLgr').text = entrega_retirada.endereco_logradouro etree.SubElement(raiz, 'nro').text = entrega_retirada.endereco_numero etree.SubElement(raiz, 'xCpl').text = entrega_retirada.endereco_complemento etree.SubElement(raiz, 'xBairro').text = entrega_retirada.endereco_bairro etree.SubElement(raiz, 'cMun').text = entrega_retirada.endereco_municipio etree.SubElement(raiz, 'xMun').text = obter_municipio_por_codigo( entrega_retirada.endereco_municipio, entrega_retirada.endereco_uf, ) etree.SubElement(raiz, 'UF').text = entrega_retirada.endereco_uf if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz
def _cabecalho_soap(self, metodo): """Monta o XML do cabeçalho da requisição SOAP""" raiz = etree.Element('nfeCabecMsg', xmlns=NAMESPACE_METODO + metodo) if metodo == 'RecepcaoEvento': etree.SubElement(raiz, 'versaoDados').text = '1.00' elif metodo == 'NfeConsultaDest': etree.SubElement(raiz, 'versaoDados').text = '1.01' elif metodo == 'NfeDownloadNF': etree.SubElement(raiz, 'versaoDados').text = '1.00' elif metodo == 'CadConsultaCadastro2': etree.SubElement(raiz, 'versaoDados').text = '2.00' else: etree.SubElement(raiz, 'versaoDados').text = VERSAO_PADRAO etree.SubElement(raiz, 'cUF').text = CODIGOS_ESTADOS[self.uf.upper()] return raiz
def construir_xml_soap(self, metodo, dados, cabecalho=False): NAMESPACE_MDFE = "http://www.portalfiscal.inf.br/mdfe/wsdl/MDFeRecepcao" """Mota o XML para o envio via SOAP""" raiz = etree.Element('{%s}Envelope' % NAMESPACE_SOAP, nsmap={ 'xsi': NAMESPACE_XSI, 'xsd': NAMESPACE_XSD, 'soap12': NAMESPACE_SOAP }) header = etree.SubElement(raiz, '{%s}Header' % NAMESPACE_SOAP) body = etree.SubElement(raiz, '{%s}Body' % NAMESPACE_SOAP) #cbcMsg = etree.SubElement(header, 'mdfeCabecMsg', xmlns=NAMESPACE_MDFE) # distribuição tem um corpo de xml diferente if metodo == 'NFeDistribuicaoDFe': print("OPS!!") #xml = etree.SubElement(body, 'nfeDistDFeInteresse', xmlns=NAMESPACE_METODO+metodo) #a = etree.SubElement(x, 'mdfeCabecMsg') else: idmdfe = "MDFe22554575125155451212132" mdfeCabec = etree.SubElement(header, 'mdfeCabecMsg', xmlns=NAMESPACE_MDFE) etree.SubElement(mdfeCabec, 'cUF').text = "22" etree.SubElement(mdfeCabec, 'versaoDados').text = "3.00" a = etree.SubElement(body, 'mdfeDadosMsg', xmlns=NAMESPACE_MDFE) #envimdfe = etree.SubElement(a, 'enviMDFe') mdfe = a #a = etree.SubElement(body, 'mdfeDadosMsg', xmlns=NAMESPACE_METODO+metodo) NAMESPACE_METODO2 = 'http://www.portalfiscal.inf.br/' mdfe.append(dados) envimdfe = mdfe.find("enviMDFe") idLote = etree.Element('idLote') root = etree.Element('MDFe') idLote.text = "1" envimdfe.insert(0, idLote) envimdfe.insert(1, root) #ide = envimdfe.find("ide") #ide, emit, infModal, infDoc, tot root.insert(0, envimdfe.find("ide")) root.insert(1, envimdfe.find("emit")) root.insert(2, envimdfe.find("infModal")) root.insert(3, envimdfe.find("infDoc")) root.insert(4, envimdfe.find("tot")) return raiz
def assinar(self, xml, retorna_string=False): # busca tag que tem id(reference_uri), logo nao importa se tem namespace reference = xml.find(".//*[@Id]").attrib['Id'] #print('Referencia: ',reference) # retira acentos xml_str = remover_acentos( etree.tostring(xml, encoding="unicode", pretty_print=False)) xml = etree.fromstring(xml_str) signer = XMLSigner( method=signxml.methods.enveloped, signature_algorithm="rsa-sha1", digest_algorithm='sha1', c14n_algorithm='http://www.w3.org/TR/2001/REC-xml-c14n-20010315') ns = {None: signer.namespaces['ds']} signer.namespaces = ns #print('Chave......: ',self.key) #print('*',200) #print('Certificado: ',self.cert) ref_uri = ('#%s' % reference) if reference else None signed_root = signer.sign(xml, key=self.key, cert=self.cert, reference_uri=ref_uri) ns = {'ns': NAMESPACE_SIG} # coloca o certificado na tag X509Data/X509Certificate tagX509Data = signed_root.find('.//ns:X509Data', namespaces=ns) etree.SubElement(tagX509Data, 'X509Certificate').text = self.cert #print('Assinatura: ',etree.tostring(signed_root, encoding="unicode", pretty_print=False) ) if retorna_string: return etree.tostring(signed_root, encoding="unicode", pretty_print=False) else: return signed_root
def _serializar_produto_servico(self, produto_servico, tag_raiz='det', retorna_string=True): raiz = etree.Element(tag_raiz) # Produto prod = etree.SubElement(raiz, 'prod') etree.SubElement(prod, 'cProd').text = str(produto_servico.codigo) etree.SubElement(prod, 'cEAN').text = produto_servico.ean etree.SubElement(prod, 'xProd').text = produto_servico.descricao etree.SubElement(prod, 'CFOP').text = produto_servico.cfop etree.SubElement(prod, 'uCom').text = produto_servico.unidade_comercial etree.SubElement(prod, 'qCom').text = str( produto_servico.quantidade_comercial or 0) etree.SubElement(prod, 'vUnCom').text = str( produto_servico.valor_unitario_comercial or 0) etree.SubElement(prod, 'vProd').text = str(produto_servico.valor_total_bruto or 0) etree.SubElement(prod, 'cEANTrib').text = produto_servico.ean_tributavel etree.SubElement(prod, 'uTrib').text = produto_servico.unidade_tributavel etree.SubElement(prod, 'qTrib').text = str( produto_servico.quantidade_tributavel) etree.SubElement(prod, 'vUnTrib').text = str( produto_servico.valor_unitario_tributavel) # Imposto imposto = etree.SubElement(raiz, 'imposto') icms = etree.SubElement(imposto, 'ICMS') icms_item = etree.SubElement( icms, 'ICMS' + produto_servico.icms_situacao_tributaria) etree.SubElement(icms_item, 'orig').text = str(produto_servico.icms_origem) etree.SubElement(icms_item, 'CST').text = produto_servico.icms_situacao_tributaria etree.SubElement(icms_item, 'modBC').text = str( produto_servico.icms_modalidade_determinacao_bc) etree.SubElement(icms_item, 'vBC').text = str( produto_servico.icms_valor_base_calculo) etree.SubElement(icms_item, 'pICMS').text = str(produto_servico.icms_aliquota) etree.SubElement(icms_item, 'vICMS').text = str(produto_servico.icms_valor) pis = etree.SubElement(imposto, 'PIS') pis_item = etree.SubElement(pis, 'PISAliq') etree.SubElement(pis_item, 'CST').text = str( produto_servico.pis_situacao_tributaria) etree.SubElement(pis_item, 'vBC').text = str( produto_servico.pis_valor_base_calculo) etree.SubElement(pis_item, 'pPIS').text = str( produto_servico.pis_aliquota_percentual) etree.SubElement(pis_item, 'vPIS').text = str(produto_servico.pis_valor) cofins = etree.SubElement(imposto, 'COFINS') cofins_item = etree.SubElement(cofins, 'COFINSAliq') etree.SubElement(cofins_item, 'CST').text = str( produto_servico.cofins_situacao_tributaria) etree.SubElement(cofins_item, 'vBC').text = str( produto_servico.cofins_valor_base_calculo) etree.SubElement(cofins_item, 'pCOFINS').text = str( produto_servico.cofins_aliquota_percentual) etree.SubElement(cofins_item, 'vCOFINS').text = str(produto_servico.cofins_valor) if retorna_string: return etree.tostring(raiz, pretty_print=True) else: return raiz
def inutilizacao(self, modelo, cnpj, numero_inicial, numero_final, justificativa='', ano=None, serie='1'): """ Serviço destinado ao atendimento de solicitações de inutilização de numeração. :param modelo: Modelo da nota :param cnpj: CNPJda empresa :param numero_inicial: Número inicial :param numero_final: Número final :param justificativa: Justificativa :param ano: Ano :param serie: Série :return: """ # url do servico url = self._get_url(modelo=modelo, consulta='INUTILIZACAO') # Valores default ano = str(ano or datetime.date.today().year)[-2:] uf = CODIGOS_ESTADOS[self.uf.upper()] cnpj = so_numeros(cnpj) # Identificador da TAG a ser assinada formada com Código da UF + Ano (2 posições) + # CNPJ + modelo + série + nro inicial e nro final precedida do literal “ID” id_unico = 'ID%(uf)s%(ano)s%(cnpj)s%(modelo)s%(serie)s%(num_ini)s%(num_fin)s' % { 'uf': uf, 'ano': ano, 'cnpj': cnpj, 'modelo': '55' if modelo == 'nfe' else '65', # 55=NF-e; 65=NFC-e; 'serie': serie.zfill(3), 'num_ini': str(numero_inicial).zfill(9), 'num_fin': str(numero_final).zfill(9), } # Monta XML do corpo da requisição # FIXME raiz = etree.Element('inutNFe', versao=VERSAO_PADRAO, xmlns=NAMESPACE_NFE) inf_inut = etree.SubElement(raiz, 'infInut', Id=id_unico) etree.SubElement(inf_inut, 'tpAmb').text = str(self._ambiente) etree.SubElement(inf_inut, 'xServ').text = 'INUTILIZAR' etree.SubElement(inf_inut, 'cUF').text = uf etree.SubElement(inf_inut, 'ano').text = ano etree.SubElement(inf_inut, 'CNPJ').text = cnpj etree.SubElement(inf_inut, 'mod').text = '55' if modelo == 'nfe' else '65' # 55=NF-e; 65=NFC-e etree.SubElement(inf_inut, 'serie').text = serie etree.SubElement(inf_inut, 'nNFIni').text = str(numero_inicial) etree.SubElement(inf_inut, 'nNFFin').text = str(numero_final) etree.SubElement(inf_inut, 'xJust').text = justificativa # assinatura a1 = AssinaturaA1(self.certificado, self.certificado_senha) xml = a1.assinar(raiz) # Monta XML para envio da requisição xml = self._construir_xml_soap('NFeInutilizacao4', xml) # Faz request no Servidor da Sefaz e retorna resposta return self._post(url, xml)
def autorizacao(self, modelo, nota_fiscal, id_lote=1, ind_sinc=1): """ Método para realizar autorização da nota de acordo com o modelo :param modelo: Modelo :param nota_fiscal: XML assinado :param id_lote: Id do lote - numero autoincremental gerado pelo sistema :param ind_sinc: Indicador de sincrono e assincrono, 0 para assincrono, 1 para sincrono :return: Uma tupla que em caso de sucesso, retorna xml com nfe e protocolo de autorização. Caso contrário, envia todo o soap de resposta da Sefaz para decisão do usuário. """ # url do serviço url = self._get_url(modelo=modelo, consulta='AUTORIZACAO') # Monta XML do corpo da requisição raiz = etree.Element('enviNFe', xmlns=NAMESPACE_NFE, versao=VERSAO_PADRAO) etree.SubElement(raiz, 'idLote').text = str(id_lote) # numero autoincremental gerado pelo sistema etree.SubElement(raiz, 'indSinc').text = str(ind_sinc) # 0 para assincrono, 1 para sincrono raiz.append(nota_fiscal) # Monta XML para envio da requisição xml = self._construir_xml_soap('NFeAutorizacao4', raiz) # Faz request no Servidor da Sefaz retorno = self._post(url, xml) # Em caso de sucesso, retorna xml com nfe e protocolo de autorização. # Caso contrário, envia todo o soap de resposta da Sefaz para decisão do usuário. if retorno.status_code == 200: # namespace ns = {'ns': NAMESPACE_NFE} # Procuta status no xml try: prot = etree.fromstring(retorno.text) except ValueError: # em SP retorno.text apresenta erro prot = etree.fromstring(retorno.content) if ind_sinc == 1: try: # Protocolo com envio OK try: inf_prot = prot[0][0] # root protNFe except IndexError: # Estados como GO vem com a tag header inf_prot = prot[1][0] lote_status = inf_prot.xpath("ns:retEnviNFe/ns:cStat", namespaces=ns)[0].text # Lote processado if lote_status == '104': prot_nfe = inf_prot.xpath("ns:retEnviNFe/ns:protNFe", namespaces=ns)[0] status = prot_nfe.xpath('ns:infProt/ns:cStat', namespaces=ns)[0].text # autorizado usa da NF-e # retorna xml final (protNFe+NFe) if status == '100': raiz = etree.Element('nfeProc', xmlns=NAMESPACE_NFE, versao=VERSAO_PADRAO) raiz.append(nota_fiscal) raiz.append(prot_nfe) return 0, raiz except IndexError: # Protocolo com algum erro no Envio return 1, retorno, nota_fiscal else: # Retorna id do protocolo para posterior consulta em caso de sucesso. rec = prot[0][0] status = rec.xpath("ns:retEnviNFe/ns:cStat", namespaces=ns)[0].text # Lote Recebido com Sucesso! if status == '103': nrec = rec.xpath("ns:retEnviNFe/ns:infRec/ns:nRec", namespaces=ns)[0].text return 0, nrec, nota_fiscal return 1, retorno, nota_fiscal
def _serializar_evento(self, evento, tag_raiz='evento', retorna_string=False): # timezone Brasília -03:00 tz = time.strftime("%z") tz = "{}:{}".format(tz[:-2], tz[-2:]) #import ipdb #ipdb.set_trace() raiz = etree.Element(tag_raiz, versao='1.00', xmlns=NAMESPACE_NFE) e = etree.SubElement(raiz, 'infEvento', Id=evento.identificador) etree.SubElement(e, 'cOrgao').text = CODIGOS_ESTADOS[evento.uf.upper()] etree.SubElement(e, 'tpAmb').text = str(self._ambiente) etree.SubElement( e, 'CNPJ').text = evento.cnpj # Empresas somente terão CNPJ #etree.SubElement(evento, 'CPF').text = '' etree.SubElement(e, 'chNFe').text = evento.chave etree.SubElement( e, 'dhEvento' ).text = evento.data_emissao.strftime('%Y-%m-%dT%H:%M:%S') + tz etree.SubElement(e, 'tpEvento').text = evento.tp_evento etree.SubElement(e, 'nSeqEvento').text = str(evento.n_seq_evento) etree.SubElement(e, 'verEvento').text = '1.00' det = etree.SubElement(e, 'detEvento', versao='1.00') etree.SubElement(det, 'descEvento').text = evento.descricao etree.SubElement(det, 'nProt').text = evento.protocolo etree.SubElement(det, 'xJust').text = evento.justificativa if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz
def inutilizar_faixa_numeracao(self, numero_inicial, numero_final, emitente, certificado, senha, ano=None, serie='1', justificativa=''): post = '/nfeweb/services/nfestatusservico.asmx' metodo = 'NfeInutilizacao2' # Valores default ano = str(ano or datetime.date.today().year)[-2:] uf = CODIGOS_ESTADOS[emitente.endereco_uf] cnpj = so_numeros(emitente.cnpj) # Identificador da TAG a ser assinada formada com Código da UF + Ano (2 posições) + # CNPJ + modelo + série + nro inicial e nro final precedida do literal “ID” id_unico = 'ID%(uf)s%(ano)s%(cnpj)s%(modelo)s%(serie)s%(num_ini)s%(num_fin)s' % { 'uf': uf, 'ano': ano, 'cnpj': cnpj, 'modelo': '55', 'serie': serie.zfill(3), 'num_ini': str(numero_inicial).zfill(9), 'num_fin': str(numero_final).zfill(9), } # Monta XML do corpo da requisição # FIXME raiz = etree.Element('inutNFe', xmlns="http://www.portalfiscal.inf.br/nfe", versao="1.07") inf_inut = etree.SubElement(raiz, 'infInut', Id=id_unico) etree.SubElement(inf_inut, 'tpAmb').text = str(self._ambiente) etree.SubElement(inf_inut, 'xServ').text = 'INUTILIZAR' etree.SubElement(inf_inut, 'cUF').text = uf etree.SubElement(inf_inut, 'ano').text = ano etree.SubElement(inf_inut, 'CNPJ').text = emitente.cnpj etree.SubElement(inf_inut, 'mod').text = '55' etree.SubElement(inf_inut, 'serie').text = serie etree.SubElement(inf_inut, 'nNFIni').text = str(numero_inicial) etree.SubElement(inf_inut, 'nNFFin').text = str(numero_final) etree.SubElement(inf_inut, 'xJust').text = justificativa #dados = etree.tostring(raiz, encoding='utf-8', xml_declaration=True) # Efetua assinatura assinatura = self._assinatura(certificado, senha) dados = assinatura.assinar_etree(etree.ElementTree(raiz), retorna_xml=True) # Monta XML para envio da requisição xml = self._construir_xml_soap( metodo='nfeRecepcao2', # XXX tag_metodo='nfeInutilizacaoNF', # XXX cabecalho=self._cabecalho_soap(), dados=dados, ) # Chama método que efetua a requisição POST no servidor SOAP retorno = self._post(post, xml, self._post_header()) # Transforma o retorno em etree # TODO #retorno = etree.parse(StringIO(retorno)) return retorno
def _serializar_emitente(self, emitente, tag_raiz='emit', retorna_string=True): raiz = etree.Element(tag_raiz) # Dados do emitente etree.SubElement(raiz, 'CNPJ').text = so_numeros(emitente.cnpj) etree.SubElement(raiz, 'xNome').text = emitente.razao_social etree.SubElement(raiz, 'xFant').text = emitente.nome_fantasia # Endereço endereco = etree.SubElement(raiz, 'enderEmit') etree.SubElement(endereco, 'xLgr').text = emitente.endereco_logradouro etree.SubElement(endereco, 'nro').text = emitente.endereco_numero if emitente.endereco_complemento: etree.SubElement(endereco, 'xCpl').text = emitente.endereco_complemento etree.SubElement(endereco, 'xBairro').text = emitente.endereco_bairro etree.SubElement(endereco, 'cMun').text = obter_codigo_por_municipio( emitente.endereco_municipio, emitente.endereco_uf) etree.SubElement(endereco, 'xMun').text = emitente.endereco_municipio etree.SubElement(endereco, 'UF').text = emitente.endereco_uf etree.SubElement(endereco, 'CEP').text = so_numeros(emitente.endereco_cep) etree.SubElement(endereco, 'cPais').text = emitente.endereco_pais etree.SubElement(endereco, 'xPais').text = obter_pais_por_codigo( emitente.endereco_pais) if emitente.endereco_telefone: etree.SubElement(endereco, 'fone').text = emitente.endereco_telefone etree.SubElement(raiz, 'IE').text = emitente.inscricao_estadual # Apenas NF-e if emitente.inscricao_estadual_subst_tributaria: etree.SubElement( raiz, 'IEST').text = emitente.inscricao_estadual_subst_tributaria # Inscricao Municipal if emitente.inscricao_municipal: etree.SubElement(raiz, 'IM').text = emitente.inscricao_municipal # Campo Opcional. Pode ser informado quando a Inscrição Municipal (id:C19) for informada. if emitente.cnae_fiscal: etree.SubElement(raiz, 'CNAE').text = emitente.cnae_fiscal etree.SubElement(raiz, 'CRT').text = emitente.codigo_de_regime_tributario if retorna_string: return etree.tostring(raiz, encoding="unicode", pretty_print=True) else: return raiz
def _serializar_notas_fiscal(self, nota_fiscal, tag_raiz='infNFe', retorna_string=True): raiz = etree.Element(tag_raiz, versao=self._versao) # Dados da Nota Fiscal ide = etree.SubElement(raiz, 'ide') etree.SubElement(ide, 'cUF').text = CODIGOS_ESTADOS[nota_fiscal.uf] etree.SubElement(ide, 'cNF').text = nota_fiscal.codigo_numerico_aleatorio etree.SubElement(ide, 'natOp').text = nota_fiscal.natureza_operacao etree.SubElement(ide, 'indPag').text = str(nota_fiscal.forma_pagamento) etree.SubElement(ide, 'mod').text = str(nota_fiscal.modelo) etree.SubElement(ide, 'serie').text = nota_fiscal.serie etree.SubElement(ide, 'nNF').text = str(nota_fiscal.numero_nf) etree.SubElement( ide, 'dEmi').text = nota_fiscal.data_emissao.strftime('%Y-%m-%d') etree.SubElement( ide, 'dSaiEnt').text = nota_fiscal.data_saida_entrada.strftime( '%Y-%m-%d') etree.SubElement(ide, 'tpNF').text = str(nota_fiscal.tipo_documento) etree.SubElement(ide, 'cMunFG').text = nota_fiscal.municipio etree.SubElement(ide, 'tpImp').text = str(nota_fiscal.tipo_impressao_danfe) etree.SubElement(ide, 'tpEmis').text = str(nota_fiscal.forma_emissao) etree.SubElement(ide, 'cDV').text = nota_fiscal.dv_codigo_numerico_aleatorio etree.SubElement(ide, 'tpAmb').text = str(self._ambiente) etree.SubElement(ide, 'finNFe').text = str(nota_fiscal.finalidade_emissao) etree.SubElement(ide, 'procEmi').text = str(nota_fiscal.processo_emissao) etree.SubElement( ide, 'verProc').text = '%s %s' % (self._nome_aplicacao, nota_fiscal.versao_processo_emissao) # Emitente raiz.append( self._serializar_emitente(nota_fiscal.emitente, retorna_string=False)) # Destinatário raiz.append( self._serializar_cliente(nota_fiscal.cliente, retorna_string=False)) # Retirada if nota_fiscal.retirada: raiz.append( self._serializar_entrega_retirada( nota_fiscal.retirada, retorna_string=False, tag_raiz='retirada', )) # Entrega if nota_fiscal.entrega: raiz.append( self._serializar_entrega_retirada( nota_fiscal.entrega, retorna_string=False, tag_raiz='entrega', )) # Itens for num, item in enumerate(nota_fiscal.produtos_e_servicos): det = self._serializar_produto_servico(item, retorna_string=False) det.attrib['nItem'] = str(num + 1) raiz.append(det) # Totais total = etree.SubElement(raiz, 'total') icms_total = etree.SubElement(total, 'ICMSTot') etree.SubElement(icms_total, 'vBC').text = str( nota_fiscal.totais_icms_base_calculo) etree.SubElement(icms_total, 'vICMS').text = str(nota_fiscal.totais_icms_total) etree.SubElement(icms_total, 'vBCST').text = str( nota_fiscal.totais_icms_st_base_calculo) etree.SubElement(icms_total, 'vST').text = str(nota_fiscal.totais_icms_st_total) etree.SubElement(icms_total, 'vProd').text = str( nota_fiscal.totais_icms_total_produtos_e_servicos) etree.SubElement(icms_total, 'vFrete').text = str( nota_fiscal.totais_icms_total_frete) etree.SubElement(icms_total, 'vSeg').text = str( nota_fiscal.totais_icms_total_seguro) etree.SubElement(icms_total, 'vDesc').text = str( nota_fiscal.totais_icms_total_desconto) etree.SubElement(icms_total, 'vII').text = str(nota_fiscal.totais_icms_total_ii) etree.SubElement(icms_total, 'vIPI').text = str(nota_fiscal.totais_icms_total_ipi) etree.SubElement(icms_total, 'vPIS').text = str(nota_fiscal.totais_icms_pis) etree.SubElement(icms_total, 'vCOFINS').text = str(nota_fiscal.totais_icms_cofins) etree.SubElement(icms_total, 'vOutro').text = str( nota_fiscal.totais_icms_outras_despesas_acessorias) etree.SubElement(icms_total, 'vNF').text = str(nota_fiscal.totais_icms_total_nota) # Transporte transp = etree.SubElement(raiz, 'transp') etree.SubElement(transp, 'modFrete').text = str( nota_fiscal.transporte_modalidade_frete) # Transportadora transp.append( self._serializar_transportadora( nota_fiscal.transporte_transportadora, retorna_string=False, )) # Veículo veiculo = etree.SubElement(transp, 'veicTransp') etree.SubElement(veiculo, 'placa').text = nota_fiscal.transporte_veiculo_placa etree.SubElement(veiculo, 'UF').text = nota_fiscal.transporte_veiculo_uf etree.SubElement(veiculo, 'RNTC').text = nota_fiscal.transporte_veiculo_rntc # Reboque reboque = etree.SubElement(transp, 'reboque') etree.SubElement(reboque, 'placa').text = nota_fiscal.transporte_reboque_placa etree.SubElement(reboque, 'UF').text = nota_fiscal.transporte_reboque_uf etree.SubElement(reboque, 'RNTC').text = nota_fiscal.transporte_reboque_rntc # Volumes for volume in nota_fiscal.transporte_volumes: vol = etree.SubElement(transp, 'vol') etree.SubElement(vol, 'qVol').text = str(volume.quantidade) etree.SubElement(vol, 'esp').text = volume.especie etree.SubElement(vol, 'marca').text = volume.marca etree.SubElement(vol, 'nVol').text = volume.numeracao etree.SubElement(vol, 'pesoL').text = str(volume.peso_liquido) etree.SubElement(vol, 'pesoB').text = str(volume.peso_bruto) # Lacres lacres = etree.SubElement(vol, 'lacres') for lacre in volume.lacres: etree.SubElement(lacres, 'nLacre').text = lacre.numero_lacre # Informações adicionais info_ad = etree.SubElement(raiz, 'infAdic') etree.SubElement( info_ad, 'infAdFisco' ).text = nota_fiscal.informacoes_adicionais_interesse_fisco etree.SubElement( info_ad, 'infCpl' ).text = nota_fiscal.informacoes_complementares_interesse_contribuinte # 'Id' da tag raiz # Ex.: NFe35080599999090910270550010000000011518005123 raiz.attrib['Id'] = nota_fiscal.identificador_unico if retorna_string: return etree.tostring(raiz, pretty_print=True) else: return raiz
def _serializar_emitente(self, emitente, tag_raiz='emit', retorna_string=True): raiz = etree.Element(tag_raiz) # Dados do emitente etree.SubElement(raiz, 'CNPJ').text = so_numeros(emitente.cnpj) etree.SubElement(raiz, 'xNome').text = emitente.razao_social etree.SubElement(raiz, 'xFant').text = emitente.nome_fantasia etree.SubElement(raiz, 'IE').text = emitente.inscricao_estadual # Endereço endereco = etree.SubElement(raiz, 'enderEmit') etree.SubElement(endereco, 'xLgr').text = emitente.endereco_logradouro etree.SubElement(endereco, 'nro').text = emitente.endereco_numero etree.SubElement(endereco, 'xCpl').text = emitente.endereco_complemento etree.SubElement(endereco, 'xBairro').text = emitente.endereco_bairro etree.SubElement(endereco, 'cMun').text = emitente.endereco_municipio etree.SubElement(endereco, 'xMun').text = obter_municipio_por_codigo( emitente.endereco_municipio, emitente.endereco_uf, ) etree.SubElement(endereco, 'UF').text = emitente.endereco_uf etree.SubElement(endereco, 'CEP').text = so_numeros(emitente.endereco_cep) etree.SubElement(endereco, 'cPais').text = emitente.endereco_pais etree.SubElement(endereco, 'xPais').text = obter_pais_por_codigo( emitente.endereco_pais) etree.SubElement(endereco, 'fone').text = emitente.endereco_telefone if retorna_string: return etree.tostring(raiz, pretty_print=True) else: return raiz