diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py index 1c8da02a..36d9eec5 100644 --- a/pynfe/processamento/serializacao.py +++ b/pynfe/processamento/serializacao.py @@ -1662,7 +1662,7 @@ def _serializar_nota_fiscal( if nota_fiscal.totais_icms_v_icms_mono_ret: etree.SubElement(icms_total, "vICMSMonoRet").text = "{:.2f}".format(nota_fiscal.totais_icms_v_icms_mono_ret) - etree.SubElement(icms_total, "vProd").text = str( + etree.SubElement(icms_total, "vProd").text = "{:.2f}".format( nota_fiscal.totais_icms_total_produtos_e_servicos ) etree.SubElement(icms_total, "vFrete").text = "{:.2f}".format( @@ -1695,7 +1695,7 @@ def _serializar_nota_fiscal( etree.SubElement(icms_total, "vOutro").text = "{:.2f}".format( nota_fiscal.totais_icms_outras_despesas_acessorias ) - etree.SubElement(icms_total, "vNF").text = str( + etree.SubElement(icms_total, "vNF").text = "{:.2f}".format( nota_fiscal.totais_icms_total_nota ) if nota_fiscal.totais_tributos_aproximado: diff --git a/tests/test_nfce_serializacao_vnf_vprod_duas_casas_decimais.py b/tests/test_nfce_serializacao_vnf_vprod_duas_casas_decimais.py new file mode 100644 index 00000000..7533e8bb --- /dev/null +++ b/tests/test_nfce_serializacao_vnf_vprod_duas_casas_decimais.py @@ -0,0 +1,173 @@ +#!/usr/bin/env python +# *-* encoding: utf8 *-* + +import datetime +import unittest +from decimal import Decimal + +from pynfe.entidades.emitente import Emitente +from pynfe.entidades.fonte_dados import _fonte_dados +from pynfe.entidades.notafiscal import NotaFiscal +from pynfe.processamento.assinatura import AssinaturaA1 +from pynfe.processamento.serializacao import SerializacaoXML +from pynfe.processamento.validacao import Validacao +from pynfe.utils.flags import ( + CODIGO_BRASIL, + NAMESPACE_NFE, + NAMESPACE_SIG, + XSD_FOLDER_NFE, + XSD_NFE, + XSD_NFE_PROCESSADA, +) + + +class SerializacaoNFeTestCase(unittest.TestCase): + """ + Imprimir o XML completo: + print(etree.tostring(self.xml_assinado)) + + """ + + def setUp(self): + self.certificado = "./tests/certificado.pfx" + self.senha = bytes("123456", "utf-8") + self.uf = "pr" + self.homologacao = True + + self.ns = {"ns": NAMESPACE_NFE} + self.ns_sig = {"ns": NAMESPACE_SIG} + + self.validacao = Validacao() + self.xsd_procNFe = self.validacao.get_xsd( + xsd_file=XSD_NFE_PROCESSADA, xsd_folder=XSD_FOLDER_NFE + ) + self.xsd_nfe = self.validacao.get_xsd( + xsd_file=XSD_NFE, xsd_folder=XSD_FOLDER_NFE + ) + + def preenche_emitente(self): + self.emitente = Emitente( + razao_social="NF-E EMITIDA EM AMBIENTE DE HOMOLOGACAO - SEM VALOR FISCAL", + nome_fantasia="Nome Fantasia da Empresa", + cnpj="99999999000199", # cnpj apenas números + codigo_de_regime_tributario="3", # 1 para simples nacional ou 3 para normal + inscricao_estadual="9999999999", # numero de IE da empresa + inscricao_municipal="12345", + cnae_fiscal="9999999", # cnae apenas números + endereco_logradouro="Rua da Paz", + endereco_numero="666", + endereco_bairro="Sossego", + endereco_municipio="Paranavaí", + endereco_uf="PR", + endereco_cep="87704000", + endereco_pais=CODIGO_BRASIL, + ) + return self.emitente + + def preenche_notafiscal_produto(self, valorUnitario, quantidade, valorTotal): + utc = datetime.timezone.utc + data_emissao = datetime.datetime(2021, 1, 14, 12, 0, 0, tzinfo=utc) + data_saida_entrada = datetime.datetime(2021, 1, 14, 13, 10, 20, tzinfo=utc) + + self.notafiscal = NotaFiscal( + emitente=self.emitente, + cliente=None, + uf="PR", + natureza_operacao="VENDA", # venda, compra, transferência, devolução, etc + forma_pagamento=0, # 0=Pagamento à vista; 1=Pagamento a prazo; 2=Outros. + tipo_pagamento=1, + modelo=65, # 55=NF-e; 65=NFC-e + serie="1", + numero_nf="111", # Número do Documento Fiscal. + data_emissao=data_emissao, + data_saida_entrada=data_saida_entrada, + tipo_documento=1, # 0=entrada; 1=saida + municipio="4118402", # Código IBGE do Município + tipo_impressao_danfe=1, # 1=DANFE normal + forma_emissao="1", # 1=Emissão normal (não em contingência); + cliente_final=1, # 0=Normal;1=Consumidor final; + indicador_destino=1, + indicador_presencial=1, + finalidade_emissao="1", # 1=NF-e normal + processo_emissao="0", # 0=Emissão de NF-e com aplicativo do contribuinte; + transporte_modalidade_frete=1, + informacoes_adicionais_interesse_fisco="Mensagem complementar", + totais_tributos_aproximado=Decimal("1.01"), + valor_troco=Decimal('3.00'), + ) + + self.notafiscal.adicionar_produto_servico( + codigo="000328", # id do produto + descricao="Produto teste", + ncm="99999999", + # cest='0100100', # NT2015/003 + ean="1234567890121", + cfop="5102", + unidade_comercial="UN", + quantidade_comercial=Decimal(quantidade), + valor_unitario_comercial=Decimal(valorUnitario), + valor_total_bruto=Decimal(valorTotal), + unidade_tributavel="UN", + quantidade_tributavel=Decimal(quantidade), + valor_unitario_tributavel=Decimal(valorUnitario), + ean_tributavel="SEM GTIN", + ind_total=1, + icms_modalidade="00", + icms_origem=0, + icms_csosn="", + pis_modalidade="51", + cofins_modalidade="51", + pis_valor_base_calculo=Decimal("0.00"), + pis_aliquota_percentual=Decimal("0.00"), + pis_valor=Decimal("0.00"), + cofins_valor_base_calculo=Decimal("0.00"), + cofins_aliquota_percentual=Decimal("0.00"), + cofins_valor=Decimal("0.00"), + valor_tributos_aprox="1.01", + ) + + def serializa_nfe(self): + serializador = SerializacaoXML( + fonte_dados=_fonte_dados, homologacao=self.homologacao, so_cpf=True + ) + return serializador.exportar() + + def assina_xml(self): + a1 = AssinaturaA1(self.certificado, self.senha) + return a1.assinar(self.xml) + + def validacao_com_xsd_do_xml_gerado_sem_processar(self): + self.validacao.validar_etree( + xml_doc=self.xml_assinado, xsd_file=self.xsd_nfe, use_assert=True + ) + + def total_test(self, valorEsperado): + vProd = self.xml_assinado.xpath( + "//ns:total/ns:ICMSTot/ns:vProd", namespaces=self.ns + )[0].text + + vNF = self.xml_assinado.xpath( + "//ns:total/ns:ICMSTot/ns:vNF", namespaces=self.ns + )[0].text + + self.assertEqual(vProd, valorEsperado) + self.assertEqual(vNF, valorEsperado) + + def test_notafiscal_produto_com_vnf_e_vprod_com_duas_casas_decimais(self): + valorUnitario = 9.67 + quantidade = 12 + valorTotal = 116.03999999999999 + valorEsperado = "116.04" + # Preenche as classes do pynfe + self.emitente = self.preenche_emitente() + self.notafiscal = self.preenche_notafiscal_produto(valorUnitario, quantidade, valorTotal) + + # Serializa e assina o XML + self.xml = self.serializa_nfe() + self.xml_assinado = self.assina_xml() + + self.assertEqual(valorUnitario * quantidade, valorTotal) + self.total_test(valorEsperado) + +if __name__ == "__main__": + unittest.main()