From f42f4a278600b2c26c14d65997dd762fe39541a7 Mon Sep 17 00:00:00 2001 From: Sasha Mitchell Date: Sat, 26 Sep 2026 12:51:06 +0700 Subject: [PATCH] Keep significant zeros in the NFC-e CSC id. SEFAZ drops only non-significant zeros. Removing every zero turned id 100 into 1, so the QR hash was for the wrong token. --- pynfe/processamento/serializacao.py | 5 ++- tests/test_nfce_qrcode_csc.py | 62 +++++++++++++++++++++++++++++ 2 files changed, 65 insertions(+), 2 deletions(-) create mode 100644 tests/test_nfce_qrcode_csc.py diff --git a/pynfe/processamento/serializacao.py b/pynfe/processamento/serializacao.py index cb463000..4862970d 100644 --- a/pynfe/processamento/serializacao.py +++ b/pynfe/processamento/serializacao.py @@ -2144,8 +2144,9 @@ def gerar_qrcode(self, token, csc, xml, return_qr=False, online=True): lista_dia = re.findall(r"-\d{2}", str(data)) dia = str(lista_dia[1]) dia = dia[1:] - replacements = {"0": ""} - token = re.sub("([0])", lambda m: replacements[m.group()], token) + # Id do CSC sem zeros nao significativos (a esquerda). Um zero que + # faz parte do identificador, como em 000100, permanece. + token = token.lstrip("0") # VERSAO_QRCODE =2 if online: diff --git a/tests/test_nfce_qrcode_csc.py b/tests/test_nfce_qrcode_csc.py new file mode 100644 index 00000000..0e063128 --- /dev/null +++ b/tests/test_nfce_qrcode_csc.py @@ -0,0 +1,62 @@ +import hashlib +import unittest + +from lxml import etree + +from pynfe.processamento.serializacao import SerializacaoQrcode +from pynfe.utils.flags import NAMESPACE_NFE, NAMESPACE_SIG, VERSAO_QRCODE +from pynfe.utils.webservices import NFCE + +CHAVE = "4" * 44 +CSC = "CSC-TEST-SECRET" + + +def _tag(namespace, name): + return f"{{{namespace}}}{name}" + + +def _nota(chave=CHAVE): + nfe = etree.Element(_tag(NAMESPACE_NFE, "NFe"), nsmap={None: NAMESPACE_NFE}) + inf = etree.SubElement(nfe, _tag(NAMESPACE_NFE, "infNFe")) + inf.set("Id", "NFe" + chave) + ide = etree.SubElement(inf, _tag(NAMESPACE_NFE, "ide")) + etree.SubElement(ide, _tag(NAMESPACE_NFE, "cUF")).text = "41" + etree.SubElement(ide, _tag(NAMESPACE_NFE, "dhEmi")).text = "2024-01-15T10:00:00-03:00" + etree.SubElement(ide, _tag(NAMESPACE_NFE, "tpAmb")).text = "1" + total = etree.SubElement(inf, _tag(NAMESPACE_NFE, "total")) + icms = etree.SubElement(total, _tag(NAMESPACE_NFE, "ICMSTot")) + etree.SubElement(icms, _tag(NAMESPACE_NFE, "vNF")).text = "10.00" + signature = etree.SubElement(nfe, _tag(NAMESPACE_SIG, "Signature")) + signed = etree.SubElement(signature, _tag(NAMESPACE_SIG, "SignedInfo")) + reference = etree.SubElement(signed, _tag(NAMESPACE_SIG, "Reference")) + etree.SubElement(reference, _tag(NAMESPACE_SIG, "DigestValue")).text = "abc=" + return nfe + + +def _parametro(qrcode): + return qrcode.split("p=", 1)[1] + + +class NfceQrCodeCscTest(unittest.TestCase): + def test_id_do_csc_preserva_zero_significativo(self): + _, qrcode = SerializacaoQrcode().gerar_qrcode( + "000100", CSC, _nota(), return_qr=True, online=True + ) + parametro = _parametro(qrcode) + campos = parametro.split("|") + self.assertEqual(campos[3], "100") + payload = "|".join(campos[:4]) + esperado = hashlib.sha1((payload + CSC).encode()).hexdigest().upper() + self.assertEqual(campos[4], esperado) + self.assertTrue(qrcode.startswith(NFCE["PR"]["QR"])) + self.assertEqual(campos[1], VERSAO_QRCODE) + + def test_id_do_csc_remove_apenas_zeros_a_esquerda(self): + _, qrcode = SerializacaoQrcode().gerar_qrcode( + "000001", CSC, _nota(), return_qr=True, online=True + ) + self.assertEqual(_parametro(qrcode).split("|")[3], "1") + + +if __name__ == "__main__": + unittest.main()