This page provides an overview of the major structural building blocks that comprise a CFDI XML document. These components are constructed from GOBL invoice data and assembled into a hierarchical XML structure that conforms to the Mexican SAT CFDI 4.0 schema.
For details on the core conversion orchestration and validation, see Core CFDI Engine. For information about document extensions such as stamps and addendas, see Document Extensions and Features.
A CFDI document consists of several mandatory and optional components that capture different aspects of an invoice transaction. The core components are:
This page describes how these components are represented in code and how they fit together. Detailed documentation for each component type is available in the child pages:
Sources: parties.go11-36 lines.go9-29 taxes.go12-43
This diagram shows how the main structs nest within the CFDI XML structure. The Document struct (defined in the core conversion module) contains top-level components, which in turn contain nested sub-components. Tax data appears at both document and line levels with identical structures.
Sources: parties.go38-96 lines.go32-64 taxes.go54-104
Each component type has a dedicated constructor function that extracts relevant data from the GOBL invoice structure and transforms it into CFDI-compliant format. These functions are invoked by the main Convert function during the document assembly process.
The party components represent the supplier and customer entities in a transaction:
| Component | Struct | Constructor | Purpose |
|---|---|---|---|
| Supplier | Emisor | newEmisor() | Issuer information with RFC and fiscal regime |
| Customer | Receptor | newReceptor() | Recipient information with postal code and CFDI use |
| Third Party | ThirdParty | newThirdParty() | Optional seller-on-behalf information |
Key Fields:
Rfc, Nombre, RegimenFiscal parties.go12-16Rfc, Nombre, DomicilioFiscalReceptor, RegimenFiscalReceptor, UsoCFDI, NumRegIdTrib (foreign), ResidenciaFiscal (foreign) parties.go19-27RFC, Name, FiscalRegime, PostCode parties.go31-36The newReceptor function handles three scenarios: simplified invoices (generic public customer), foreign customers, and standard Mexican business customers parties.go60-96 For detailed party processing logic, see Party Management (Emisor and Receptor).
Sources: parties.go11-96 parties_test.go11-65
Line items represent the products or services being invoiced:
| Component | Struct | Constructor | Purpose |
|---|---|---|---|
| Line List | Conceptos | newConceptos() | Container for all line items |
| Individual Line | Concepto | newConcepto() | Single product/service entry |
Key Fields:
ClaveProdServ: SAT product/service codeNoIdentificacion: Item referenceCantidad: QuantityClaveUnidad: SAT unit of measure codeDescripcion: Item descriptionValorUnitario: Unit priceImporte: Line total (quantity × price)Descuento: Discount amount (optional)ObjetoImp: Tax applicability indicator ("01" = not subject to tax, "02" = subject to tax)Impuestos: Line-level tax breakdownThirdParty: Third-party seller information (optional)Sources: lines.go9-72
The ObjetoImp field is computed by lineSubjectToTax() which returns "02" if the line has any taxes applied, otherwise "01" lines.go66-71 For detailed line processing including SAT code mapping, see Line Items (Conceptos).
Tax information appears at two levels in the document:
| Level | Component | Purpose |
|---|---|---|
| Document | Impuestos | Aggregated tax totals for entire invoice |
| Line | ConceptoImpuestos | Tax breakdown for individual line item |
Both levels share common structures:
Sources: taxes.go12-43
Tax Categories:
The taxCategoryMap translates GOBL tax categories to SAT tax codes taxes.go46-52:
| GOBL Category | SAT Code | Description |
|---|---|---|
mx.TaxCategoryISR | "001" | Income tax (ISR) |
tax.CategoryVAT | "002" | Value-added tax (IVA) |
mx.TaxCategoryRVAT | "002" | Retained VAT |
mx.TaxCategoryIEPS | "003" | Special tax on production/services |
mx.TaxCategoryRIEPS | "003" | Retained IEPS |
Impuesto Struct Fields:
Base: Taxable amountImporte: Calculated tax amountImpuesto: SAT tax code ("001", "002", "003")TasaOCuota: Tax rate or quotaTipoFactor: Factor type ("Tasa", "Cuota", "Exento")For complete tax calculation logic including special IEPS handling, see Tax Processing System.
Sources: taxes.go12-52
Payment information is stored directly in the Document struct rather than in a separate component:
| Field | Type | Purpose |
|---|---|---|
MetodoPago | string | Payment method code (PUE = single payment, PPD = partial/deferred) |
FormaPago | string | Payment form code (01 = cash, 03 = transfer, 04 = credit card, etc.) |
These values are determined by the newMetodoPago and newFormaPago functions, which analyze payment advances and invoice totals to select appropriate codes. For detailed payment determination logic, see Payment Information.
Sources: cfdi.go162-201 (referenced in architecture diagrams)
Sources: taxes.go54-104 taxes.go180-215 lines.go32-64
This diagram illustrates the parallel processing of document-level and line-level data. Document-level taxes are calculated from invoice totals, while line-level taxes are computed for each individual line item. Both processes use shared helper functions like newImpuesto() to ensure consistent tax entry formatting.
A special case in tax processing is the handling of IEPS line charges, which must be merged into the document-level tax totals:
Sources: taxes.go106-143
The taxesAddLineCharges function iterates through all line charges (currently only IEPS charges), creates tax entries for them, and either merges them into existing tax totals (if matching tax code and rate exist) or appends them as new entries taxes.go106-143 This ensures that IEPS charges, which appear at the line level in GOBL, are properly aggregated into document-level tax totals as required by CFDI.
The following table summarizes the primary constructor functions for each component type:
| Function | Input | Output | Location |
|---|---|---|---|
newEmisor() | *org.Party | *Emisor | parties.go38-45 |
newReceptor() | *org.Party, string | *Receptor | parties.go60-96 |
newThirdParty() | *org.Party | *ThirdParty | parties.go47-58 |
newConceptos() | []*bill.Line, *bill.Ordering | *Conceptos | lines.go32-43 |
newConcepto() | *bill.Line, *bill.Ordering | *Concepto | lines.go45-64 |
newImpuestos() | *bill.Totals, []*bill.Line, currency.Code | *Impuestos | taxes.go54-104 |
newConceptoImpuestos() | *bill.Line | *ConceptoImpuestos | taxes.go180-215 |
newImpuesto() | cbc.Code, *tax.RateTotal, currency.Code | *Impuesto | taxes.go160-178 |
newImpuestoFromCombo() | *bill.Line, *tax.Combo | *Impuesto | taxes.go217-242 |
newImpuestoFromLineCharge() | *bill.Line, *bill.LineCharge | *Impuesto | taxes.go244-272 |
Sources: parties.go38-96 lines.go32-64 taxes.go54-272
These constructor functions are invoked by the main cfdi.Convert function during the document assembly process. Each function is responsible for extracting relevant data from GOBL structures, performing necessary transformations (such as code mapping and rounding), and returning properly formatted CFDI component structs.
Components must adhere to specific validation rules to produce valid CFDI XML:
Emisor Requirements:
RegimenFiscal)Receptor Requirements:
DomicilioFiscalReceptor)UsoCFDI)NumRegIdTrib and ResidenciaFiscalConcepto Requirements:
ClaveProdServ)ClaveUnidad)ObjetoImp)Impuesto Requirements:
TipoFactor must be "Tasa", "Cuota", or "Exento"For validation logic executed before component construction, see Validation and Support Checking.
Sources: parties.go38-96 lines.go45-64 taxes.go160-178
The CFDI document is composed of several interdependent components that work together to create a complete, SAT-compliant XML invoice. The core components are:
Emisor, Receptor, ThirdParty) - Entity informationConceptos, Concepto) - Product/service detailsImpuestos, ConceptoImpuestos, Impuesto) - Tax calculationsMetodoPago, FormaPago) - Payment method codesEach component is constructed from GOBL invoice data using dedicated constructor functions that handle data transformation, code mapping, and precision adjustments. The components are assembled into a hierarchical structure that mirrors the CFDI XML schema, with taxes appearing at both document and line levels.
For in-depth documentation on each component type, refer to the child pages listed in the table of contents.
Refresh this wiki