def _prepare_eletronic_invoice_values(self): if self.model not in ('nfe', 'nfce'): return tz = timezone(self.env.user.tz or 'America/Sao_Paulo') dt_emissao = datetime.now(tz).replace(microsecond=0).isoformat() dt_saida = fields.Datetime.from_string(self.data_entrada_saida) if dt_saida: dt_saida = tz.localize(dt_saida).replace(microsecond=0).isoformat() else: dt_saida = dt_emissao ide = { 'cUF': self.company_id.state_id.l10n_br_ibge_code, 'cNF': "%08d" % self.numero_controle, 'natOp': self.natureza_operacao, 'mod': '55' if self.model == 'nfe' else '65', 'serie': self.serie_documento, 'nNF': self.numero, 'dhEmi': dt_emissao, 'dhSaiEnt': dt_saida, 'tpNF': '0' if self.tipo_operacao == 'entrada' else '1', 'idDest': self.ind_dest or 1, 'cMunFG': "%s%s" % (self.company_id.state_id.l10n_br_ibge_code, self.company_id.city_id.l10n_br_ibge_code), # Formato de Impressão do DANFE - 1 - Danfe Retrato, 4 - Danfe NFCe 'tpImp': '1' if self.model == 'nfe' else '4', 'tpEmis': int(self.tipo_emissao), 'tpAmb': 2 if self.ambiente == 'homologacao' else 1, 'finNFe': self.finalidade_emissao, 'indFinal': self.ind_final or '1', 'indPres': self.ind_pres or '1', 'procEmi': 0, 'verProc': 'Odoo 11 - Trustcode', } # Documentos Relacionados documentos = [] for doc in self.related_document_ids: data = fields.Datetime.from_string(doc.date) if doc.document_type == 'nfe': documentos.append({'refNFe': doc.access_key}) elif doc.document_type == 'nf': documentos.append({ 'refNF': { 'cUF': doc.state_id.l10n_br_ibge_code, 'AAMM': data.strftime("%y%m"), 'CNPJ': re.sub('[^0-9]', '', doc.cnpj_cpf), 'mod': doc.fiscal_document_id.code, 'serie': doc.serie, 'nNF': doc.internal_number, } }) elif doc.document_type == 'cte': documentos.append({'refCTe': doc.access_key}) elif doc.document_type == 'nfrural': cnpj_cpf = re.sub('[^0-9]', '', doc.cnpj_cpf) documentos.append({ 'refNFP': { 'cUF': doc.state_id.l10n_br_ibge_code, 'AAMM': data.strftime("%y%m"), 'CNPJ': cnpj_cpf if len(cnpj_cpf) == 14 else '', 'CPF': cnpj_cpf if len(cnpj_cpf) == 11 else '', 'IE': doc.inscr_est, 'mod': doc.fiscal_document_id.code, 'serie': doc.serie, 'nNF': doc.internal_number, } }) elif doc.document_type == 'cf': documentos.append({ 'refECF': { 'mod': doc.fiscal_document_id.code, 'nECF': doc.serie, 'nCOO': doc.internal_number, } }) ide['NFref'] = documentos emit = { 'tipo': self.company_id.partner_id.company_type, 'cnpj_cpf': re.sub('[^0-9]', '', self.company_id.l10n_br_cnpj_cpf), 'xNome': self.company_id.l10n_br_legal_name, 'xFant': self.company_id.name, 'enderEmit': { 'xLgr': self.company_id.street, 'nro': self.company_id.l10n_br_number, 'xCpl': self.company_id.street2 or '', 'xBairro': self.company_id.l10n_br_district, 'cMun': '%s%s' % (self.company_id.partner_id.state_id.l10n_br_ibge_code, self.company_id.partner_id.city_id.l10n_br_ibge_code), 'xMun': self.company_id.city_id.name, 'UF': self.company_id.state_id.code, 'CEP': re.sub('[^0-9]', '', self.company_id.zip), 'cPais': self.company_id.country_id.l10n_br_ibge_code, 'xPais': self.company_id.country_id.name, 'fone': re.sub('[^0-9]', '', self.company_id.phone or '') }, 'IE': re.sub('[^0-9]', '', self.company_id.l10n_br_inscr_est), 'IEST': re.sub('[^0-9]', '', self.iest or ''), 'CRT': self.cod_regime_tributario, } if self.company_id.l10n_br_cnae_main_id and self.company_id.l10n_br_inscr_mun: emit['IM'] = re.sub('[^0-9]', '', self.company_id.l10n_br_inscr_mun or '') emit['CNAE'] = re.sub( '[^0-9]', '', self.company_id.l10n_br_cnae_main_id.code or '') dest = None exporta = None if self.commercial_partner_id: partner = self.commercial_partner_id dest = { 'tipo': partner.company_type, 'cnpj_cpf': re.sub('[^0-9]', '', partner.l10n_br_cnpj_cpf or ''), 'xNome': partner.l10n_br_legal_name or partner.name, 'enderDest': { 'xLgr': partner.street, 'nro': partner.l10n_br_number, 'xCpl': partner.street2 or '', 'xBairro': partner.l10n_br_district, 'cMun': '%s%s' % (partner.state_id.l10n_br_ibge_code, partner.city_id.l10n_br_ibge_code), 'xMun': partner.city_id.name, 'UF': partner.state_id.code, 'CEP': re.sub('[^0-9]', '', partner.zip or ''), 'cPais': (partner.country_id.l10n_br_ibge_code or '')[-4:], 'xPais': partner.country_id.name, 'fone': re.sub('[^0-9]', '', partner.phone or '') }, 'indIEDest': self.ind_ie_dest, 'IE': re.sub('[^0-9]', '', partner.l10n_br_inscr_est or ''), 'ISUF': partner.l10n_br_suframa or '', } if self.model == 'nfce': dest.update({ 'CPF': re.sub('[^0-9]', '', partner.l10n_br_cnpj_cpf or '') }) if self.ambiente == 'homologacao': dest['xNome'] = \ u'NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO -\ SEM VALOR FISCAL' if partner.country_id.id != self.company_id.country_id.id: dest['idEstrangeiro'] = re.sub('[^0-9]', '', partner.l10n_br_cnpj_cpf or '') dest['enderDest']['UF'] = 'EX' dest['enderDest']['xMun'] = 'Exterior' dest['enderDest']['cMun'] = '9999999' dest['enderDest']['CEP'] = '' exporta = { 'UFSaidaPais': self.uf_saida_pais_id.code or '', 'xLocExporta': self.local_embarque or '', 'xLocDespacho': self.local_despacho or '', } autorizados = [] if self.company_id.l10n_br_accountant_id: autorizados.append({ 'CNPJ': re.sub('[^0-9]', '', self.company_id.l10n_br_accountant_id.l10n_br_cnpj_cpf) }) eletronic_items = [] for item in self.document_line_ids: eletronic_items.append( self._prepare_eletronic_invoice_item(item, self)) total = { # ICMS 'vBC': "%.02f" % self.valor_bc_icms, 'vICMS': "%.02f" % self.valor_icms, 'vICMSDeson': '0.00', 'vFCP': '0.00', # TODO Implementar aqui 'vBCST': "%.02f" % self.valor_bc_icmsst, 'vST': "%.02f" % self.valor_icmsst, 'vFCPST': '0.00', 'vFCPSTRet': '0.00', 'vProd': "%.02f" % sum(self.document_line_ids.mapped("valor_bruto")), 'vFrete': "%.02f" % self.valor_frete, 'vSeg': "%.02f" % self.valor_seguro, 'vDesc': "%.02f" % self.valor_desconto, 'vII': "%.02f" % self.valor_ii, 'vIPI': "%.02f" % self.valor_ipi, 'vIPIDevol': '0.00', 'vPIS': "%.02f" % self.pis_valor, 'vCOFINS': "%.02f" % self.cofins_valor, 'vOutro': "%.02f" % self.valor_despesas, 'vNF': "%.02f" % self.valor_final, 'vFCPUFDest': "%.02f" % self.valor_icms_fcp_uf_dest, 'vICMSUFDest': "%.02f" % self.valor_icms_uf_dest, 'vICMSUFRemet': "%.02f" % self.valor_icms_uf_remet, 'vTotTrib': "%.02f" % self.valor_estimado_tributos, } if self.valor_servicos > 0.0: issqn_total = { 'vServ': "%.02f" % self.valor_servicos if self.valor_servicos else "", 'vBC': "%.02f" % self.iss_base_calculo if self.iss_base_calculo else "", 'vISS': "%.02f" % self.iss_valor if self.iss_valor else "", 'vPIS': "%.02f" % self.pis_valor if self.pis_valor else "", 'vCOFINS': "%.02f" % self.cofins_valor if self.cofins_valor else "", 'dCompet': dt_emissao[:10], 'vDeducao': "", 'vOutro': "", 'vISSRet': "%.02f" % self.iss_valor_retencao if self.iss_valor_retencao else '', } tributos_retidos = { 'vRetPIS': "%.02f" % self.iss_valor_retencao if self.iss_valor_retencao else '', 'vRetCOFINS': "%.02f" % self.cofins_valor_retencao if self.cofins_valor_retencao else '', 'vRetCSLL': "%.02f" % self.csll_valor_retencao if self.csll_valor_retencao else '', 'vBCIRRF': "%.02f" % self.irrf_base_calculo if self.irrf_valor_retencao else '', 'vIRRF': "%.02f" % self.irrf_valor_retencao if self.irrf_valor_retencao else '', 'vBCRetPrev': "%.02f" % self.inss_base_calculo if self.inss_valor_retencao else '', 'vRetPrev': "%.02f" % self.inss_valor_retencao if self.inss_valor_retencao else '', } if self.transportadora_id.street: end_transp = "%s - %s, %s" % ( self.transportadora_id.street, self.transportadora_id.l10n_br_number or '', self.transportadora_id.l10n_br_district or '') else: end_transp = '' transp = { 'modFrete': self.modalidade_frete, 'transporta': { 'xNome': self.transportadora_id.l10n_br_legal_name or self.transportadora_id.name or '', 'IE': re.sub('[^0-9]', '', self.transportadora_id.l10n_br_inscr_est or ''), 'xEnder': end_transp if self.transportadora_id else '', 'xMun': self.transportadora_id.city_id.name or '', 'UF': self.transportadora_id.state_id.code or '' }, 'veicTransp': { 'placa': self.placa_veiculo or '', 'UF': self.uf_veiculo or '', 'RNTC': self.rntc or '', } } cnpj_cpf = re.sub('[^0-9]', '', self.transportadora_id.l10n_br_cnpj_cpf or '') if self.transportadora_id.is_company: transp['transporta']['CNPJ'] = cnpj_cpf else: transp['transporta']['CPF'] = cnpj_cpf reboques = [] for item in self.reboque_ids: reboques.append({ 'placa': item.placa_veiculo or '', 'UF': item.uf_veiculo or '', 'RNTC': item.rntc or '', 'vagao': item.vagao or '', 'balsa': item.balsa or '', }) transp['reboque'] = reboques volumes = [] for item in self.volume_ids: volumes.append({ 'qVol': item.quantidade_volumes or '', 'esp': item.especie or '', 'marca': item.marca or '', 'nVol': item.numeracao or '', 'pesoL': "%.03f" % item.peso_liquido if item.peso_liquido else '', 'pesoB': "%.03f" % item.peso_bruto if item.peso_bruto else '', }) transp['vol'] = volumes duplicatas = [] for dup in self.duplicata_ids: vencimento = fields.Datetime.from_string(dup.data_vencimento) duplicatas.append({ 'nDup': dup.numero_duplicata, 'dVenc': vencimento.strftime('%Y-%m-%d'), 'vDup': "%.02f" % dup.valor }) cobr = { 'fat': { 'nFat': self.numero_fatura or '', 'vOrig': "%.02f" % (self.fatura_liquido + self.fatura_desconto), 'vDesc': "%.02f" % self.fatura_desconto, 'vLiq': "%.02f" % self.fatura_liquido, }, 'dup': duplicatas } pag = { 'indPag': '0', # TODO colocar a prazo se tiver mais de uma parcela 'tPag': '90', # TODO Verificar esse campo aqui 'vPag': '0.00', } infAdic = { 'infCpl': self.informacoes_complementares or '', 'infAdFisco': self.informacoes_legais or '', } compras = { 'xNEmp': self.nota_empenho or '', 'xPed': self.pedido_compra or '', 'xCont': self.contrato_compra or '', } responsavel_tecnico = self.company_id.l10n_br_responsavel_tecnico_id infRespTec = {} if responsavel_tecnico: cnpj = re.sub('[^0-9]', '', responsavel_tecnico.l10n_br_cnpj_cpf) fone = re.sub('[^0-9]', '', responsavel_tecnico.phone or '') infRespTec = { 'CNPJ': cnpj or '', 'xContato': responsavel_tecnico.child_ids[0].name or '', 'email': responsavel_tecnico.email or '', 'fone': fone, 'idCSRT': self.company_id.l10n_br_id_token_csrt or '', 'hashCSRT': self._get_hash_csrt() or '', } vals = { 'Id': '', 'ide': ide, 'emit': emit, 'dest': dest, 'autXML': autorizados, 'detalhes': eletronic_items, 'total': total, 'pag': [pag], 'transp': transp, 'infAdic': infAdic, 'exporta': exporta, 'compra': compras, 'infRespTec': infRespTec, } if self.valor_servicos > 0.0: vals.update({ 'ISSQNtot': issqn_total, 'retTrib': tributos_retidos, }) if len(duplicatas) > 0 and\ self.fiscal_position_id.finalidade_emissao not in ('2', '4'): vals['cobr'] = cobr pag['tPag'] = '01' if pag['tPag'] == '90' else pag['tPag'] pag['vPag'] = "%.02f" % self.valor_final if self.model == 'nfce': vals['pag'][0]['tPag'] = self.metodo_pagamento vals['pag'][0]['vPag'] = "%.02f" % self.valor_pago vals['pag'][0]['vTroco'] = "%.02f" % self.troco or '0.00' chave_nfe = self.chave_nfe ambiente = 1 if self.ambiente == 'producao' else 2 estado = self.company_id.state_id.l10n_br_ibge_code cid_token = int(self.company_id.l10n_br_id_token_csc) csc = self.company_id.l10n_br_csc c_hash_QR_code = "{0}|2|{1}|{2}{3}".format(chave_nfe, ambiente, int(cid_token), csc) c_hash_QR_code = hashlib.sha1(c_hash_QR_code.encode()).hexdigest() QR_code_url = "p={0}|2|{1}|{2}|{3}".format(chave_nfe, ambiente, int(cid_token), c_hash_QR_code) qr_code_server = url_qrcode(estado, str(ambiente)) vals['qrCode'] = qr_code_server + QR_code_url vals['urlChave'] = url_qrcode_exibicao(estado, str(ambiente)) return vals
def gerar_qrcode(id_csc: int, csc: str, xml_send: str, cert = False) -> str: xml = etree.fromstring(xml_send) signature = xml.find( ".//{http://www.w3.org/2000/09/xmldsig#}Signature") id = xml.find( ".//{http://www.portalfiscal.inf.br/nfe}infNFe").get('Id') if id is None: raise Exception("XML Invalido - Sem o ID") chave = id.replace('NFe', '') emit_uf = chave[:2] tp_amb = xml.find(".//{http://www.portalfiscal.inf.br/nfe}tpAmb") if tp_amb is None: raise Exception("XML Invalido - Sem o tipo de ambiente") dh_emi = xml.find(".//{http://www.portalfiscal.inf.br/nfe}dhEmi") if dh_emi is None: raise Exception("XML Invalido - Sem data de Emissao") dh_emi = dh_emi.text.split("-")[2].split("T")[0] tp_emis = xml.find(".//{http://www.portalfiscal.inf.br/nfe}tpEmis") if tp_emis is None: raise Exception("XML Invalido - Sem tipo de emissao") v_nf = xml.find(".//{http://www.portalfiscal.inf.br/nfe}vNF") if v_nf is None: raise Exception("XML Invalido - Sem o valor da NFe") url_qrcode_str = url_qrcode( estado=emit_uf, ambiente=tp_amb.text) url_qrcode_exibicao_str = url_qrcode_exibicao( estado=emit_uf, ambiente=tp_amb.text) if tp_emis != 1: if signature is None: if cert is not False: signer = Assinatura(certificado.pfx, certificado.password) xml_send = signer.assina_xml(xmlElem_send, id) else: raise Exception("XML Invalido - Sem assinatura e não " "foi enviado o certificado nos parametros") digest_value = xml.find( ".//{http://www.w3.org/2000/09/xmldsig#}DigestValue") c_hash_qr_code = \ "{ch_acesso}|{versao}|{tp_amb}|{dh_emi}|" \ "{v_nf}|{dig_val}|{id_csc}|{csc}".format( ch_acesso=chave, versao=2, tp_amb=tp_amb.text, dh_emi=dh_emi, v_nf=float(v_nf.text), dig_val=digest_value.text, id_csc=int(id_csc), csc=csc ) c_hash_qr_code = hashlib.sha1(c_hash_qr_code.encode()). \ hexdigest() qr_code_url = 'p={ch_acesso}|{versao}|{tp_amb}|{dh_emi}|" \ "{v_nf}|{dig_val}|{id_csc}|{hash}'.format( ch_acesso=chave, versao=2, tp_amb=tp_amb.text, dh_emi=dh_emi, v_nf=float(v_nf.text), dig_val=digest_value.text, id_csc=int(id_csc), hash=c_hash_qr_code ) qrcode = url_qrcode_str + qr_code_url url_consulta = url_qrcode_exibicao_str qrCode = xml.find( './/{http://www.portalfiscal.inf.br/nfe}qrCode').text = \ qrcode urlChave = xml.find( './/{http://www.portalfiscal.inf.br/nfe}urlChave').text = \ url_consulta else: c_hash_qr_code = \ "{ch_acesso}|{versao}|{tp_amb}|{id_csc}|{csc}".format( ch_acesso=chave, versao=2, tp_amb=tp_amb.text, id_csc=int(id_csc), csc=csc ) c_hash_qr_code = hashlib.sha1(c_hash_qr_code.encode()).hexdigest() qr_code_url = "p={ch_acesso}|{versao}|{tp_amb}|{id_csc}|" \ "{hash}".\ format( ch_acesso=chave, versao=2, tp_amb=tp_amb.text, id_csc=int(id_csc), hash=c_hash_qr_code ) qrcode = url_qrcode_str + qr_code_url url_consulta = url_qrcode_exibicao_str qrCode = xml.find( './/{http://www.portalfiscal.inf.br/nfe}qrCode').text = \ qrcode urlChave = xml.find( './/{http://www.portalfiscal.inf.br/nfe}urlChave').text = \ url_consulta return etree.tostring(xml)