Install satcfdi via pip
mainYou can install the satcfdi package directly from PyPI using pip. Ensure you have a supported version of Python installed before running the command.
python -m pip install satcfdirepository·main·Indexed 41 days ago
https://github.com/sat-cfdi/python-satcfdiAn open-source Python library for generating and processing Mexican SAT CFDI (Comprobante Fiscal Digital por Internet) documents, supporting versions 3.2, 3.3, and 4.0. It provides tools to create invoices, payroll, and payment documents, sign them using digital certificates, and export them to XML, JSON, HTML, and PDF formats.
You can install the satcfdi package directly from PyPI using pip. Ensure you have a supported version of Python installed before running the command.
python -m pip install satcfdiTo install the package from the source code, clone the repository and install it using pip from the root directory.
git clone https://github.com/SAT-CFDI/python-satcfdi
cd python-satcfdi
python -m pip install .To request a mass download of CFDIs you have issued (emitted), use sat_service.recover_comprobante_emitted_request().
Required Parameters:
fecha_inicial: Start date (datetime.date).fecha_final: End date (datetime.date).rfc_emisor: The RFC of the issuer (can be retrieved via sat_service.signer.rfc).tipo_solicitud: Use TipoDescargaMasivaTerceros.CFDI.estado_comprobante: Use EstadoComprobante.VIGENTE (mandatory for CFDI downloads).The response contains an IdSolicitud which must be stored to check the status later.
from datetime import date
from satcfdi.pacs.sat import SAT, TipoDescargaMasivaTerceros, EstadoComprobante
sat_service = SAT(signer=signer)
response = sat_service.recover_comprobante_emitted_request(
fecha_inicial=date(2020, 1, 1),
fecha_final=date(2020, 12, 1),
rfc_emisor=sat_service.signer.rfc,
tipo_solicitud=TipoDescargaMasivaTerceros.CFDI,
estado_comprobante=EstadoComprobante.VIGENTE,
)
id_solicitud = response['IdSolicitud']To interact with SAT services, you must first authenticate using a digital certificate (FIEL or CSD). Use Signer.load() to create a Signer instance by providing the certificate file content, the private key file content, and the password as strings or bytes.
from satcfdi.models import Signer
signer = Signer.load(
certificate=open('path/to/cert.cer', 'rb').read(),
key=open('path/to/key.key', 'rb').read(),
password=open('path/to/password.txt', 'r').read()
)Payroll documents are created using the cfdi40.Comprobante.nomina() factory method. This method requires a complemento_nomina object (from nomina12.Nomina) which contains specific employee data, perceptions, and deductions.
Key steps:
cfdi40.Comprobante.nomina(...).complemento_nomina with percepciones and deducciones.from datetime import date
from decimal import Decimal
from satcfdi.models import Signer
from satcfdi.create.cfd import cfdi40, nomina12
# Load signing certificate
signer = Signer.load(
certificate=open('csd/xiqb891116qe4_csd.cer', 'rb').read(),
key=open('csd/xiqb891116qe4_csd.key', 'rb').read(),
password=open('csd/xiqb891116qe4_csd.txt', 'r').read()
)
# create Comprobante
invoice = cfdi40.Comprobante.nomina(
emisor=cfdi40.Emisor(
rfc=signer.rfc,
nombre=signer.legal_name,
regimen_fiscal="601"
),
receptor=cfdi40.Receptor(
rfc='KIJ0906199R1',
nombre='KIJ, S.A DE C.V.',
uso_cfdi='G03',
domicilio_fiscal_receptor="59820",
regimen_fiscal_receptor="601"
),
lugar_expedicion="56820",
complemento_nomina=nomina12.Nomina(
emisor=nomina12.Emisor(
registro_patronal='Z1234567890'
),
receptor=nomina12.Receptor(
cuenta_bancaria='0001000200030004',
curp='XIQB891116MCHZRL72',
clave_ent_fed='MOR',
num_empleado='12345678',
periodicidad_pago='04',
tipo_contrato='01',
tipo_regimen='02'
),
percepciones=nomina12.Percepciones(
percepcion=nomina12.Percepcion(
tipo_percepcion='001',
clave='001',
concepto='SUELDO',
importe_gravado=Decimal('1200'),
importe_exento=Decimal('400')
)
),
deducciones=nomina12.Deducciones(
deduccion=nomina12.Deduccion(
tipo_deduccion='002',
clave='300',
concepto='ISR A CARGO',
importe=Decimal('1234.73')
)
),
tipo_nomina='O',
fecha_pago=date(2020, 1, 30),
fecha_final_pago=date(2020, 1, 31),
fecha_inicial_pago=date(2020, 1, 16),
num_dias_pagados=Decimal('16.000')
),
serie="A",
folio="123456"
)
invoice.sign(signer)
invoice = invoice.process()You can install the library from PyPI using pip, or install directly from the source repository.
From PyPI:
python -m pip install satcfdiFrom Source:
git clone https://github.com/SAT-CFDI/python-satcfdi
cd python-satcfdi
python -m pip install .python -m pip install satcfdiTo create a standard CFDI 4.0 invoice, instantiate cfdi40.Comprobante with the required emisor (issuer), receptor (receiver), and conceptos (concepts/items). After instantiation, you must call .sign(signer) using a loaded Signer object, followed by .process() to finalize the document.
Key components include:
emisor: Uses signer.rfc and signer.legal_name for convenience.receptor: Requires rfc, nombre, uso_cfdi, domicilio_fiscal_receptor, and regimen_fiscal_receptor.conceptos: A list of cfdi40.Concepto objects containing product/service keys, quantities, and impuestos (taxes).from decimal import Decimal
from satcfdi.models import Signer
from satcfdi.create.cfd import cfdi40
from satcfdi.create.cfd.catalogos import RegimenFiscal, UsoCFDI, MetodoPago, Impuesto, TipoFactor
# Load signing certificate
signer = Signer.load(
certificate=open('csd/xiqb891116qe4_csd.cer', 'rb').read(),
key=open('csd/xiqb891116qe4_csd.key', 'rb').read(),
password=open('csd/xiqb891116qe4_csd.txt', 'r').read()
)
# create Comprobante
invoice = cfdi40.Comprobante(
emisor=cfdi40.Emisor(
rfc=signer.rfc,
nombre=signer.legal_name,
regimen_fiscal=RegimenFiscal.GENERAL_DE_LEY_PERSONAS_MORALES
),
lugar_expedicion="56820",
receptor=cfdi40.Receptor(
rfc='KIJ0906199R1',
nombre='KIJ, S.A DE C.V.',
uso_cfdi=UsoCFDI.GASTOS_EN_GENERAL,
domicilio_fiscal_receptor="59820",
regimen_fiscal_receptor=RegimenFiscal.GENERAL_DE_LEY_PERSONAS_MORALES
),
metodo_pago=MetodoPago.PAGO_EN_PARCIALIDADES_O_DIFERIDO,
serie="A",
folio="123456",
conceptos=[
cfdi40.Concepto(
clave_prod_serv='84111506',
cantidad=Decimal('1.00'),
clave_unidad='E48',
descripcion='SERVICIOS DE FACTURACION',
valor_unitario=Decimal('1250.30'),
impuestos=cfdi40.Impuestos(
traslados=cfdi40.Traslado(
impuesto=Impuesto.IVA,
tipo_factor=TipoFactor.TASA,
tasa_o_cuota=Decimal('0.160000'),
),
retenciones=[
cfdi40.Retencion(
impuesto=Impuesto.ISR,
tipo_factor=TipoFactor.TASA,
tasa_o_cuota=Decimal('0.100000'),
),
cfdi40.Retencion(
impuesto=Impuesto.IVA,
tipo_factor=TipoFactor.TASA,
tasa_o_cuota=Decimal('0.106667'),
)
],
)
)
]
)
invoice.sign(signer)
invoice = invoice.process()To create a payment document, use the cfdi40.Comprobante.pago() factory method. This requires a complemento_pago object (from pago20.Pagos) which contains the payment details and related documents (docto_relacionado).
from datetime import date, datetime
from decimal import Decimal
from satcfdi.models import Signer
from satcfdi.create.cfd import cfdi40, pago20
# Load signing certificate
signer = Signer.load(
certificate=open('csd/xiqb891116qe4_csd.cer', 'rb').read(),
key=open('csd/xiqb891116qe4_csd.key', 'rb').read(),
password=open('csd/xiqb891116qe4_csd.txt', 'r').read()
)
# create Comprobante
invoice = cfdi40.Comprobante.pago(
emisor=cfdi40.Emisor(
rfc=signer.rfc,
nombre=signer.legal_name,
regimen_fiscal="601"
),
receptor=cfdi40.Receptor(
rfc='KIJ0906199R1',
nombre='KIJ, S.A DE C.V.',
uso_cfdi='G03',
domicilio_fiscal_receptor="59820",
regimen_fiscal_receptor="601"
),
lugar_expedicion="56820",
complemento_pago=pago20.Pagos(
pago=pago20.Pago(
fecha_pago=datetime(2020, 1, 1),
forma_de_pago_p='03',
moneda_p='MXN',
tipo_cambio_p=1,
docto_relacionado=pago20.DoctoRelacionado(
id_documento='d6042dc8-d525-4e78-8d1b-092c878bd518',
imp_pagado=Decimal("100.3"),
imp_saldo_ant=Decimal("203.45"),
num_parcialidad=3,
moneda_dr="MXN",
objeto_imp_dr="01"
)
)
),
serie="A",
folio="123456"
)
invoice.sign(signer)
invoice = invoice.process()To interact with the SAT Factura Electrónica portal, you must first create a Signer instance using your electronic signature files (FIEL/CSD) and then initialize a SATFacturaElectronica session.
Signer.load() providing the raw bytes of the .cer certificate, the .key private key, and the password string.signer instance to SATFacturaElectronica()..login() to establish the session.from satcfdi.models import Signer
from satcfdi.portal import SATFacturaElectronica
# Load Fiel
signer = Signer.load(
certificate=open('csd/xiqb891116qe4.cer', 'rb').read(),
key=open('csd/xiqb891116qe4.key', 'rb').read(),
password=open('csd/xiqb891116qe4.txt', 'r').read()
)
sat_session = SATFacturaElectronica(signer)
sat_session.login()Use csf.retrieve to fetch the data for a Constancia de Situación Fiscal. You must provide the RFC and the id_cif identifier.
from satcfdi import csf
res = csf.retrieve("AAA010101AAA", id_cif="012345678")Once you have a loaded Signer instance, you can use the Certifica class to generate a certificate request. This is used to interact with SAT processes for obtaining or renewing certificates.
Initialize Certifica with your Signer instance and call solicitud_certificado with the following parameters:
sucursal: The branch name (e.g., "MiSucursal").password: The password to be used for the request.dirname: The directory where files should be saved (set to None to return data without saving to disk).from satcfdi.models import Signer
from satcfdi.certifica import Certifica
# 1. Load the credentials
fiel = Signer.load(
certificate=open('csd/xiqb891116qe4.cer', 'rb').read(),
key=open('csd/xiqb891116qe4.key', 'rb').read(),
password=open('csd/xiqb891116qe4.txt', 'r').read()
)
# 2. Initialize Certifica
certifica = Certifica(fiel)
# 3. Generate the request
certifica.solicitud_certificado(
sucursal="MiSucursal",
password="IsTHisSecure!32?",
dirname=None
)To request a mass download of Retentions you have issued, use sat_service.recover_retencion_emitted_request().
Required Parameters:
fecha_inicial: Start date (datetime.date).fecha_final: End date (datetime.date).rfc_emisor: The RFC of the issuer.tipo_solicitud: Use TipoDescargaMasivaTerceros.CFDI.The response contains an IdSolicitud which must be stored to check the status later.
from datetime import date
from satcfdi.pacs.sat import SAT, TipoDescargaMasivaTerceros
sat_service = SAT(signer=signer)
response = sat_service.recover_retencion_emitted_request(
fecha_inicial=date(2020, 1, 1),
fecha_final=date(2020, 12, 1),
rfc_emisor=sat_service.signer.rfc,
tipo_solicitud=TipoDescargaMasivaTerceros.CFDI,
)
id_solicitud = response['IdSolicitud']