nfelib

repository·master·Indexed 41 days ago

https://github.com/akretion/nfelib

A Python library for reading, managing, and serializing Brazilian electronic fiscal XML documents, including NF-e, NFS-e, CT-e, MDF-e, and BP-e. It leverages xsdata for high-performance data binding from XSD schemas and provides functionality for XML schema validation, PKCS#12 certificate signing, and DANFE PDF generation.

Tokens
2.7K
Snippets
12
Records
13
Agent score
3%

What's inside nfelib

  1. How nfelib manages schema versions

    master

    nfelib uses a 2-digit versioning system for its schema folders (e.g., v4_0).

    • Minor updates: Changes that do not affect the first two digits of the version are stored in the same folder, allowing newer schemas to overlap older ones (e.g., a newer version of 4.00 can read an older 4.00 file).
    • Major updates: Changes affecting the first two digits (e.g., moving from 3.1 to 4.0) are stored in separate folders, allowing the library to support multiple major versions simultaneously (e.g., emitting version 5.0 while importing version 4.0).
  2. Use CommonMixin to manage XML documents

    master

    The CommonMixin class provides shared functionality for all XML document types in nfelib (such as NF-e, CT-e, etc.). It handles parsing, schema validation, XML signing, and serialization. When working with specific document bindings, you can rely on these methods to move between XML strings, files, and Python objects.

    Key capabilities include:

    • Parsing: Convert XML strings or files into Python objects.
    • Validation: Validate XML against the appropriate XSD schema.
    • Signing: Sign XML using a PKCS#12 certificate.
    • Serialization: Convert Python objects back to XML or even PDF.
    # Example of how a document class (inheriting CommonMixin) might be used
    # (Note: Actual document classes are imported from specific submodules)
    from nfelib.nfe.bindings.nfe_v4_00 import NFe
    
    # Parsing from XML string
    nfe = NFe.from_xml(xml_string)
    
    # Parsing from a file path
    nfe = NFe.from_path("path/to/document.xml")
    
    # Validating the XML
    errors = nfe.validate_xml()
    if errors:
        print(f"Validation failed: {errors}")
  3. Create and validate an NF-e from scratch

    master

    You can instantiate new NF-e objects by passing the required nested data structures. After constructing the object, use .validate_xml() to check if the object conforms to the expected XML schema. It returns a list of error messages if validation fails.

    from nfelib.nfe.bindings.v4_0.nfe_v4_00 import Nfe
    
    # Constructing a new NFe
    nfe = Nfe(infNFe=Nfe.InfNfe(emit=Nfe.InfNfe.Emit(xNome="Minha Empresa", CNPJ='59594315000157')))
    
    # Validate the XML structure
    errors = nfe.validate_xml()
    if errors:
        print(errors)
  4. Read and serialize MDF-e, CT-e, and BP-e

    master

    The library provides similar patterns for other document types:

    • MDF-e: from nfelib.mdfe.bindings.v3_0.mdfe_v3_00 import Mdfe
    • CT-e: from nfelib.cte.bindings.v4_0.cte_v4_00 import Cte
    • BP-e: from nfelib.bpe.bindings.v1_0.bpe_v1_00 import Bpe
    # MDF-e
    from nfelib.mdfe.bindings.v3_0.mdfe_v3_00 import Mdfe
    mdfe = Mdfe.from_path("path.xml")
    
    # CT-e
    from nfelib.cte.bindings.v4_0.cte_v4_00 import Cte
    cte = Cte.from_path("path.xml")
    
    # BP-e
    from nfelib.bpe.bindings.v1_0.bpe_v1_00 import Bpe
    bpe = Bpe.from_path("path.xml")
  5. Read and serialize NFS-e (National Standard)

    master

    Use the Nfse or Dps bindings to handle National Standard Service Invoices (NFS-e) and Service Provision Declarations (DPS).

    # NFS-e
    from nfelib.nfse.bindings.v1_0.nfse_v1_00 import Nfse
    nfse = Nfse.from_path("alguma_nfse.xml")
    xml_out = nfse.to_xml()
    
    # DPS
    from nfelib.nfse.bindings.v1_0.dps_v1_00 import Dps
    dps = Dps.from_path("alguma_dps.xml")
    dps_xml = dps.to_xml()
  6. Read and serialize NF-e XML documents

    master

    Use NfeProc to read an existing NF-e XML file or XML string. You can access document fields directly as Python objects and serialize the object back to XML using .to_xml().

    To read from a file, use NfeProc.from_path(path). To read from a string, use NfeProc.from_xml(xml_string).

    from nfelib.nfe.bindings.v4_0.proc_nfe_v4_00 import NfeProc
    
    # Read from path
    nfe_proc = NfeProc.from_path("path/to/nfe.xml")
    
    # Access data
    cnpj = nfe_proc.NFe.infNFe.emit.CNPJ
    
    # Serialize back to XML
    xml_output = nfe_proc.to_xml()
  7. Generate DANFE PDF

    master

    Generate a DANFE (Documento Auxiliar da Nota Fiscal Eletrônica) PDF using the .to_pdf() method.

    • By default, it uses BrazilFiscalReport.
    • You can specify an engine like erpbrasil.edoc.pdf via the engine parameter.
    • You can perform signing and PDF generation in a single call by providing pkcs12_data, pkcs12_password, and doc_id.
    # Using default engine (BrazilFiscalReport)
    pdf_bytes = nfe.to_pdf()
    
    # Using erpbrasil.edoc.pdf engine
    pdf_bytes = nfe.to_pdf(engine="erpbrasil.edoc.pdf")
    
    # Sign and generate PDF in one step
    pdf_bytes = nfe.to_pdf(
        pkcs12_data=cert_data,
        pkcs12_password=cert_password,
        doc_id=nfe.NFe.infNFe.Id,
    )
  8. Sign an NF-e XML

    master

    To sign an XML document, use the .sign_xml() method. This requires a PKCS12 certificate and the specific ID of the document (e.g., nfe.NFe.infNFe.Id). This method is compatible with other electronic documents in the library.

    # Requires erpbrasil.assinatura
    with open(path_to_your_pkcs12_certificate, "rb") as pkcs12_buffer:
        pkcs12_data = pkcs12_buffer.read()
    
    signed_xml = nfe.sign_xml(xml, pkcs12_data, cert_password, nfe.NFe.infNFe.Id)
  9. Validate XML against XSD schemas

    master

    You can validate XML content against the official XSD schemas provided by the library.

    • schema_validation(xml: str, schema_path: str | None = None) -> list: Returns a list of error messages if validation fails. If schema_path is not provided, it automatically selects the correct schema based on the document type (e.g., NF-e v4.0, CT-e v4.0).
    • validate_xml(schema_path: str | None = None) -> list: A convenience method on the document instance that serializes the current object to XML and then validates it.
    # Validate an XML string directly
    errors = MyDocument.schema_validation(xml_string)
    
    # Validate the current object instance
    errors = my_doc_instance.validate_xml()
  10. Sign XML using PKCS#12 certificates

    master

    To sign XML documents, use the sign_xml method or pass certificate credentials to to_xml or to_pdf.

    Requirements: Requires the erpbrasil.assinatura package to be installed.

    Methods:

    • sign_xml(xml: str, pkcs12_data: bytes | None = None, pkcs12_password: str | None = None, doc_id: str | None = None) -> str: Returns the signed XML string.
    • to_xml(..., pkcs12_data: bytes | None = None, pkcs12_password: str | None = None, doc_id: str | None = None) -> str: Serializes the object and automatically signs the resulting XML if certificate data is provided.

    Environment Variables: For testing, you can use CERT_FILE and CERT_PASSWORD environment variables instead of passing arguments explicitly.

    # Signing during serialization
    xml_signed = my_doc.to_xml(
        pkcs12_data=cert_bytes, 
        pkcs12_password="password", 
        doc_id="ID_123"
    )
  11. Parse XML into Python objects with from_xml and from_path

    master

    Use these class methods to instantiate document objects from XML data.

    • from_xml(xml: str, config: ParserConfig = None) -> Any: Parses an XML string. You can provide an optional xsdata.formats.dataclass.parsers.config.ParserConfig object.
    • from_path(path: str) -> Any: Reads an XML file from the specified filesystem path and parses it.
    # From string
    obj = MyDocument.from_xml(xml_content)
    
    # From file
    obj = MyDocument.from_path("document.xml")