Mexico: CFDI
Mexico is outside the EU; CFDI 4.0 (and 3.3 in older files) is supported because it is a clearance format with the same withholding and extra-tax concerns. cfdi:Comprobante with TipoDeComprobante I is an invoice and E (egreso) a credit note. T (traslado), P (pago, Pagos 1.0/2.0) and N (nómina) are not invoices: detection returns them as other documents with their own label, and convert reports not-an-invoice.
| CFDI | Canonical |
|---|---|
Emisor / Receptor Rfc |
nationalTaxIds with scheme MX:RFC (no vatId: Mexican IVA has no VAT number). NumRegIdTrib of a foreign receiver is a second national id |
RegimenFiscal, RegimenFiscalReceptor, DomicilioFiscalReceptor, UsoCFDI, ResidenciaFiscal, LugarExpedicion, Exportacion, MetodoPago, FormaPago, InformacionGlobal, issuer Sello / NoCertificado |
extensions.mx. The receiver’s postal code is also buyer.address.postalCode; the issuer has no address in a CFDI |
Concepto |
lines: ClaveProdServ is an item classification (MX:ClaveProdServ), ClaveUnidad is unitCode (SAT’s catalogue is UN/ECE Rec 20 plus a few SAT codes) and Unidad is unitText; ObjetoImp and ClaveUnidad are kept in line.national. Descuento is a line allowance and netAmount is Importe - Descuento |
| Traslado IVA (002) | vatBreakdown and line.vat: Tasa 0.16 is S with rate 16, Tasa 0 is Z, Exento is E. ObjetoImp 01 gives O |
| Traslado IEPS (003) and others | otherTaxes (MX:IEPS, includedInTotal) |
| Retenciones ISR (001), IVA (002), IEPS (003) | withholdings (MX:ISR, MX:IVA), totals.withholdingTotal; the line-level base and rate are on line.withholdings |
SubTotal, Descuento, Total |
lineNetTotal = taxExclusive = SubTotal - Descuento, payable = Total, taxInclusive = Total + retenciones. The original SubTotal and Descuento are in extensions.mx |
FormaPago |
payments[]: 01 cash (10), 02 cheque (20), 03 transfer (30), 04 credit card (54), 28 debit card (55); the rest are ZZZ with the SAT label |
CfdiRelacionados |
precedingInvoices: the UUID is id and clearanceId, TipoRelacion is relationType (01 credit note, 04 substitution…) |
TimbreFiscalDigital |
clearance with authority MX:SAT: UUID, FechaTimbrado, NoCertificadoSAT, SelloSAT (not verified), and the PAC (RfcProvCertif) as intermediary |
What the model cannot say, and where it goes:
- No generic tax model. Every CFDI tax fits
vatBreakdown,otherTaxesorwithholdings, but two things are lost in shape. IEPS as a fixed amount per unit (TipoFactorCuota) has no rate:otherTaxes[].rateis left out andMX-TAX-CUOTAis warned (the amount and the quantity base are kept). Document-level retenciones state no base or rate in a CFDI, sowithholdings[].taxableAmountandrateare empty there; the lines carry them. - Local taxes (complement Impuestos Locales, for example the lodging tax) change
Totalbut are not mapped, so the BR-CO-15 / 16 totals check will warn on such files;MX-COMPLEMENT-UNMAPPEDnames the complement. The same warning covers Comercio Exterior, Carta Porte, INE and every other complement except the stamp. - IVA
Exentohas noImporte; the breakdown uses a tax amount of 0. CFDI 3.3 states noBaseat document level, so it is summed from the lines (recorded insource.derived). Fechahas no time zone; the time goes toissueTimeas written. Amounts are inMoneda;TipoCambio(conversion to MXN) isexchangeRate.- The issuer’s
Sellois a digital seal over the original string, not an XML signature, and is not verified. The same holds forSelloSAT. Addenda,Parte,ACuentaTercerosandComplementoConceptoare not mapped.
Run scripts/sweep.ts over a few months of your real inbound files before building phase 2. It shows which formats you actually receive.