cfdi

package module
v0.62.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 6, 2026 License: Apache-2.0 Imports: 25 Imported by: 0

README

GOBL ➡️ Mexico CFDI

Mexican CFDI (Comprobante Fiscal Digital por Internet) support for GOBL: the GOBL addon (extensions, normalizers, scenarios, and validation rules) plus the converter that turns a GOBL envelope into SAT-compliant CFDI XML — and parses it back.

Released publicly under the Apache 2.0 LICENSE, Copyright Invopop Ltd. 2023. For commercial licenses please contact the dev team at invopop. In order to accept contributions to this library we will require transferring copyrights to Invopop Ltd.

Lint Test Go Go Report Card codecov GoDoc Latest Tag Ask DeepWiki

The addon/ package implements the extensions, normalizers, scenarios, and validation rules that GOBL documents need in order to comply with the Mexican tax authority (SAT) CFDI v4.0 standard:

  • CFDI v4 (mx-cfdi-v4) — invoices, payments, and the SAT extensions (mx-cfdi-*) required to issue and stamp a Comprobante Fiscal Digital por Internet.

It also ships the CFDI complements as GOBL documents:

  • FuelAccountBalanceEstado de Cuenta de Combustibles for electronic fuel wallets.
  • FoodVouchersVales de Despensa food voucher reports.

Layout

  • addon/ — the GOBL addon: extensions, normalizers, scenarios, validation rules, and the CFDI complement documents that register into GOBL on import. Importing it registers the mx-cfdi-* addon keys in GOBL's global registry.
  • the module root — the converter that turns a GOBL envelope into CFDI XML and parses CFDI XML back into GOBL, plus addendas and a command-line tool.

Usage

Addon

Unlike the converter, this is a true GOBL addon: it registers extensions, normalizers, and validation rules into GOBL's global registry. Add a blank import so it registers itself, then use GOBL as normal:

import (
    "github.com/invopop/gobl"
    _ "github.com/invopop/gobl.mx.cfdi/addon"
)

Declare the addon on a document (or let the regime/scenario add it) and Calculate + Validate will run the full CFDI normalization and rules. The converter imports the addon automatically, so consumers that only convert do not need the blank import.

Note: the mx-cfdi-* keys are listed in GOBL core's approved external-addon registry, so they are recognised as valid $addons values in the JSON Schema. The runtime check stays strict, however: a document declaring an mx-cfdi-* addon will fail validation with add-on must be registered unless this module (the addon package) is imported. Any service that processes Mexican CFDI documents must import it.

Converter

Usage of the CFDI conversion library is quite straight forward. You must first have a GOBL Envelope including an invoice for Mexico ready to convert. There are some samples here in the test/data directory.

package main

import (
    "os"

    "github.com/invopop/gobl"
    "github.com/invopop/gobl.mx.cfdi"
)

func main() {
    data, _ := os.ReadFile("./test/data/invoice.json")

    env := new(gobl.Envelope)
    if err := json.Unmarshal(data, env); err != nil {
        panic(err)
    }

    // Prepare the CFDI document
    doc, err := cfdi.NewDocument(env)
    if err != nil {
        panic(err)
    }

    // Create the XML output
    out, err := doc.Bytes()
    if err != nil {
        panic(err)
    }

    // TODO: do something with the output
}
Testing

This package uses lestrrat-go/libxml2 for testing purporses, which in turn depends on the libxml-2.0 C library. Ensure you have the development dependency installed. In linux this implies:

sudo apt-get install libxml2-dev

Tests can take a while to run as they download the complete XML documents to test against, please be patient.

Addendas

For details on support for converting Addendas, please see the addendas package.

Command Line

The GOBL to CFDI tool also includes a command line helper. You can find pre-built gobl.mx.cfdi binaries in the github repository, or install manually in your Go environment with:

go install ./cmd/gobl.mx.cfdi

Usage is very straightforward:

gobl.mx.cfdi convert ./test/data/invoice-b2b-bare.json

Which should produce something like:

<?xml version="1.0" encoding="UTF-8"?>
<cfdi:Comprobante xmlns:cfdi="http://www.sat.gob.mx/cfd/4" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.sat.gob.mx/cfd/4 http://www.sat.gob.mx/sitio_internet/cfd/4/cfdv40.xsd" Version="4.0" TipoDeComprobante="I" Serie="LMC" Folio="0010" Fecha="2023-05-29T00:00:00" LugarExpedicion="26015" SubTotal="400.40" Descuento="200.20" Total="232.23" Moneda="MXN" Exportacion="01" MetodoPago="PUE" FormaPago="03" CondicionesDePago="Pago a 30 días." Sello="" NoCertificado="00000000000000000000" Certificado="">
  <cfdi:Emisor Rfc="EKU9003173C9" Nombre="ESCUELA KEMPER URGATE" RegimenFiscal="601"></cfdi:Emisor>
  <cfdi:Receptor Rfc="URE180429TM6" Nombre="UNIVERSIDAD ROBOTICA ESPAÑOLA" DomicilioFiscalReceptor="65000" RegimenFiscalReceptor="601" UsoCFDI="G01"></cfdi:Receptor>
  <cfdi:Conceptos>
    <cfdi:Concepto ClaveProdServ="50211502" Cantidad="2" ClaveUnidad="H87" Descripcion="Cigarros" ValorUnitario="200.2020" Importe="400.4040" Descuento="200.2020" ObjetoImp="02">
      <cfdi:Impuestos>
        <cfdi:Traslados>
          <cfdi:Traslado Base="200.2020" Importe="32.0323" Impuesto="002" TasaOCuota="0.160000" TipoFactor="Tasa"></cfdi:Traslado>
        </cfdi:Traslados>
      </cfdi:Impuestos>
    </cfdi:Concepto>
  </cfdi:Conceptos>
  <cfdi:Impuestos TotalImpuestosTrasladados="32.03">
    <cfdi:Traslados>
      <cfdi:Traslado Base="200.20" Importe="32.03" Impuesto="002" TasaOCuota="0.160000" TipoFactor="Tasa"></cfdi:Traslado>
    </cfdi:Traslados>
  </cfdi:Impuestos>
</cfdi:Comprobante>

License

Apache 2.0 — see LICENSE.

Documentation

Overview

Package cfdi implements the conversion from GOBL to CFDI XML

Package cfdi implements the conversion from CFDI XML to GOBL.

Index

Constants

View Source
const (
	CFDINamespace      = "http://www.sat.gob.mx/cfd/4"
	CFDISchemaLocation = "http://www.sat.gob.mx/sitio_internet/cfd/4/cfdv40.xsd"
	XSINamespace       = "http://www.w3.org/2001/XMLSchema-instance"
	CFDIVersion        = "4.0"
)

CFDI schema constants

View Source
const (
	FakeNoCertificado   = "00000000000000000000"
	ExportacionNoAplica = "01"
	FormaPagoPorDefinir = "99"
	ImpuestoIVA         = "002"
)

Hard-coded values for (yet) unsupported mappings

View Source
const (
	NombreReceptorGenerico       = "PÚBLICO EN GENERAL"
	RegimenFiscalSinObligaciones = "616" // no tax obligations
	UsoCFDISinEfectos            = "S01" // no tax effects
)

Generic supplier constants

View Source
const (
	TipoFactorTasa   = "Tasa"
	TipoFactorCuota  = "Cuota" // Not supported
	TipoFactorExento = "Exento"
)

TipoFactor definitions.

View Source
const (
	ObjetoImpNo = "01" // not subject to tax
	ObjetoImpSi = "02" // subject to tax
)

Subject to tax constants

View Source
const (
	VDVersion        = "1.0"
	VDTipoOperacion  = "monedero electrónico"
	VDNamespace      = "http://www.sat.gob.mx/valesdedespensa"
	VDSchemaLocation = "http://www.sat.gob.mx/sitio_internet/cfd/valesdedespensa/valesdedespensa.xsd"
)

VD Schema constants

View Source
const (
	ECCVersion        = "1.2"
	ECCTipoOperacion  = "Tarjeta"
	ECCNamespace      = "http://www.sat.gob.mx/EstadoDeCuentaCombustible12"
	ECCSchemaLocation = "http://www.sat.gob.mx/sitio_internet/cfd/EstadoDeCuentaCombustible/ecc12.xsd"
)

ECC Schema constants

View Source
const (
	TimbreNamespace      = "http://www.sat.gob.mx/TimbreFiscalDigital"
	TimbreSchemaLocation = "http://www.sat.gob.mx/sitio_internet/cfd/TimbreFiscalDigital/TimbreFiscalDigitalv11.xsd"
	TimbreVersion        = "1.1"
)

TimbreFiscalDigital namespace and schema constants

Variables

View Source
var ErrNotSupported = errors.New("not supported")

ErrNotSupported is returned when the conversion of the invoice is not supported

View Source
var (
	// ErrUnknownDocumentType is returned when the document namespace is not the expected one.
	ErrUnknownDocumentType = fmt.Errorf("unknown document namespace")
)

Functions

func Parse

func Parse(data []byte) (*gobl.Envelope, error)

Parse parses a raw CFDI XML document and converts it into a GOBL envelope. The TimbreFiscalDigital, if present, is parsed as GOBL stamps. The resulting envelope must be signed to make it valid.

func Stamp

func Stamp(env *gobl.Envelope, doc *Document) error

Stamp takes the provided structured stamp data and applies it to the envelope. This should be done after the CFDI document has been processed and signed by a PAC (Proveedor Autorizado de Certificación) in Mexico.

Types

type CFDIRelacionado

type CFDIRelacionado struct {
	UUID string `xml:",attr"`
}

CFDIRelacionado stores the data of a preceding CFDI document

type CFDIRelacionados

type CFDIRelacionados struct {
	TipoRelacion    string            `xml:",attr"`
	CfdiRelacionado []CFDIRelacionado `xml:"cfdi:CfdiRelacionado"`
}

CFDIRelacionados list the preceding CFDI documents (e.g., the preceding invoices of a credit note)

type Concepto

type Concepto struct {
	ClaveProdServ string      `xml:",attr"`
	Ref           string      `xml:"NoIdentificacion,attr,omitempty"`
	Cantidad      string      `xml:",attr"`
	ClaveUnidad   string      `xml:",attr"`
	Desc          string      `xml:"Descripcion,attr"` // nolint:misspell
	ValorUnitario num.Amount  `xml:",attr"`
	Importe       num.Amount  `xml:",attr"`
	Descuento     *num.Amount `xml:",attr,omitempty"`
	ObjetoImp     string      `xml:",attr"`

	Impuestos  *ConceptoImpuestos `xml:"cfdi:Impuestos,omitempty"`
	ThirdParty *ThirdParty        `xml:"cfdi:ACuentaTerceros,omitempty"`
}

Concepto stores an invoice line data

type ConceptoImpuestos

type ConceptoImpuestos struct {
	Traslados   *Traslados   `xml:"cfdi:Traslados,omitempty"`
	Retenciones *Retenciones `xml:"cfdi:Retenciones,omitempty"`
}

ConceptoImpuestos store the line tax totals

type Conceptos

type Conceptos struct {
	Concepto []*Concepto `xml:"cfdi:Concepto"`
}

Conceptos list invoice lines nolint:misspell

type Document

type Document struct {
	XMLName        xml.Name `xml:"cfdi:Comprobante"`
	CFDINamespace  string   `xml:"xmlns:cfdi,attr"`
	XSINamespace   string   `xml:"xmlns:xsi,attr"`
	ECCNamespace   string   `xml:"xmlns:ecc12,attr,omitempty"`
	VDNamespace    string   `xml:"xmlns:valesdedespensa,attr,omitempty"`
	SchemaLocation string   `xml:"xsi:schemaLocation,attr"`
	Version        string   `xml:"Version,attr"`

	TipoDeComprobante string      `xml:",attr"`
	Serie             string      `xml:",attr,omitempty"`
	Folio             string      `xml:",attr,omitempty"`
	Fecha             string      `xml:",attr"`
	LugarExpedicion   string      `xml:",attr"`
	SubTotal          num.Amount  `xml:",attr"`
	Descuento         *num.Amount `xml:",attr,omitempty"`
	Total             num.Amount  `xml:",attr"`
	Moneda            string      `xml:",attr"`
	TipoCambio        *num.Amount `xml:",attr,omitempty"`
	Exportacion       string      `xml:",attr"`
	MetodoPago        string      `xml:",attr,omitempty"`
	FormaPago         string      `xml:",attr,omitempty"`
	CondicionesDePago string      `xml:",attr,omitempty"`
	Sello             string      `xml:",attr"`
	NoCertificado     string      `xml:",attr"`
	Certificado       string      `xml:",attr"`

	Global           *GlobalInformation `xml:"cfdi:InformacionGlobal,omitempty"`
	CFDIRelacionados *CFDIRelacionados  `xml:"cfdi:CfdiRelacionados,omitempty"`
	Emisor           *Emisor            `xml:"cfdi:Emisor"`
	Receptor         *Receptor          `xml:"cfdi:Receptor"`
	Conceptos        *Conceptos         `xml:"cfdi:Conceptos"` //nolint:misspell
	Impuestos        *Impuestos         `xml:"cfdi:Impuestos,omitempty"`

	// Supported complements
	ComplementoValesDeDespensa         *ValesDeDespensa           `xml:"cfdi:Complemento>valesdedespensa:ValesDeDespensa,omitempty"`
	ComplementoEstadoCuentaCombustible *EstadoDeCuentaCombustible `xml:"cfdi:Complemento>ecc12:EstadoDeCuentaCombustible,omitempty"`
	ComplementoTimbreFiscalDigital     *TimbreFiscalDigital       `xml:"cfdi:Complemento>tfd:TimbreFiscalDigital,omitempty"`

	// Supported addendas
	AddendaMabe *addendas.MabeFactura `xml:"cfdi:Addenda>mabe:Factura,omitempty"`
}

Document is a pseudo-model for containing the XML document being created

func Convert

func Convert(env *gobl.Envelope) (*Document, error)

Convert converts a GOBL envelope into a CFDI document

func (*Document) Bytes

func (d *Document) Bytes() ([]byte, error)

Bytes returns the XML representation of the document in bytes

type ECCConcepto

type ECCConcepto struct {
	Identificador     string `xml:",attr"`
	Fecha             string `xml:",attr"`
	Rfc               string `xml:",attr"`
	ClaveEstacion     string `xml:",attr"`
	Cantidad          string `xml:",attr"`
	TipoCombustible   string `xml:",attr"`
	Unidad            string `xml:",attr,omitempty"`
	NombreCombustible string `xml:",attr"`
	FolioOperacion    string `xml:",attr"`
	ValorUnitario     string `xml:",attr"`
	Importe           string `xml:",attr"`

	Traslados []*ECCTraslado `xml:"ecc12:Traslados>ecc12:Traslado"`
}

ECCConcepto stores the data of a fuel purchase

type ECCTraslado

type ECCTraslado struct {
	Impuesto   string `xml:",attr"`
	TasaOCuota string `xml:",attr"`
	Importe    string `xml:",attr"`
}

ECCTraslado stores the tax data of a fuel purchase

type Emisor

type Emisor struct {
	Rfc           string `xml:",attr"`
	Nombre        string `xml:",attr"`
	RegimenFiscal string `xml:",attr"`
}

Emisor stores the invoice supplier data

type EstadoDeCuentaCombustible

type EstadoDeCuentaCombustible struct {
	XMLName       xml.Name `xml:"ecc12:EstadoDeCuentaCombustible"`
	Version       string   `xml:",attr"`
	TipoOperacion string   `xml:",attr"`

	NumeroDeCuenta string `xml:",attr"`
	SubTotal       string `xml:",attr"`
	Total          string `xml:",attr"`

	Conceptos []*ECCConcepto `xml:"ecc12:Conceptos>ecc12:ConceptoEstadoDeCuentaCombustible"` // nolint:misspell
}

EstadoDeCuentaCombustible stores the fuel account balance data

type GlobalInformation

type GlobalInformation struct {
	Period string `xml:"Periodicidad,attr"`
	Month  string `xml:"Meses,attr"`
	Year   string `xml:"Año,attr"`
}

GlobalInformation is used for invoices that contain a summary of B2C documents.

type Impuesto

type Impuesto struct {
	Base       *num.Amount `xml:",attr,omitempty"`
	Importe    *num.Amount `xml:",attr,omitempty"`
	Impuesto   string      `xml:",attr"`
	TasaOCuota *num.Amount `xml:",attr,omitempty"`
	TipoFactor string      `xml:",attr,omitempty"`
}

Impuesto stores the tax data of the invoice or a line

type Impuestos

type Impuestos struct {
	TotalImpuestosTrasladados *num.Amount  `xml:",attr,omitempty"`
	TotalImpuestosRetenidos   *num.Amount  `xml:",attr,omitempty"`
	Retenciones               *Retenciones `xml:"cfdi:Retenciones,omitempty"`
	Traslados                 *Traslados   `xml:"cfdi:Traslados,omitempty"`
}

Impuestos store the invoice tax totals

type Receptor

type Receptor struct {
	Rfc                     string `xml:",attr"`
	Nombre                  string `xml:",attr"`
	DomicilioFiscalReceptor string `xml:",attr"`
	RegimenFiscalReceptor   string `xml:",attr"`
	UsoCFDI                 string `xml:",attr"`
	NumRegIdTrib            string `xml:",attr,omitempty"` //nolint:staticcheck,revive
	ResidenciaFiscal        string `xml:",attr,omitempty"`
}

Receptor stores the invoice customer data

type Retenciones

type Retenciones struct {
	Retencion []*Impuesto `xml:"cfdi:Retencion"`
}

Retenciones lists the retained taxes of a line or the invoice

type ThirdParty

type ThirdParty struct {
	RFC          string   `xml:"RfcACuentaTerceros,attr"`
	Name         string   `xml:"NombreACuentaTerceros,attr"`
	FiscalRegime cbc.Code `xml:"RegimenFiscalACuentaTerceros,attr"`
	PostCode     cbc.Code `xml:"DomicilioFiscalACuentaTerceros,attr"`
}

ThirdParty or "ACuentaTerceros" defines the details of a third part for whom this transaction has been performed.

type TimbreFiscalDigital

type TimbreFiscalDigital struct {
	// Version is the version of the TimbreFiscalDigital standard (fixed at "1.1")
	Version string `xml:"Version,attr"`

	// UUID is the fiscal folio (36-character UUID) of the stamping transaction
	// conforming to RFC 4122 standard
	UUID string `xml:"UUID,attr"`

	// FechaTimbrado is the date and time when the stamp was generated by the SAT
	// certification. Format: YYYY-MM-DDThh:mm:ss in Mexico Central Time Zone
	FechaTimbrado string `xml:"FechaTimbrado,attr"`

	// RfcProvCertif is the RFC of the digital fiscal certificate provider
	// that generates the fiscal stamp
	RfcProvCertif string `xml:"RfcProvCertif,attr"`

	// Leyenda is an optional field to record information that the SAT
	// communicates to CFDI users (12-150 characters)
	Leyenda string `xml:"Leyenda,attr,omitempty"`

	// SelloCFD contains the digital seal of the CFDI that has been stamped,
	// expressed as a Base64 encoded string
	SelloCFD string `xml:"SelloCFD,attr"`

	// NoCertificadoSAT is the serial number of the SAT certificate used to
	// generate the digital seal of the fiscal stamp (20 digits)
	NoCertificadoSAT string `xml:"NoCertificadoSAT,attr"`

	// SelloSAT contains the digital seal of the fiscal stamp itself,
	// expressed as a Base64 encoded string
	SelloSAT string `xml:"SelloSAT,attr"`
}

TimbreFiscalDigital represents the digital fiscal stamp (Timbre Fiscal Digital) that validates a CFDI document.

type Traslados

type Traslados struct {
	Traslado []*Impuesto `xml:"cfdi:Traslado"`
}

Traslados lists the non-retained taxes of a line or the invoice

type VDConcepto

type VDConcepto struct {
	Identificador      string `xml:"identificador,attr"`
	Fecha              string `xml:"fecha,attr"`
	Rfc                string `xml:"rfc,attr"`
	Curp               string `xml:"curp,attr"`
	Nombre             string `xml:"nombre,attr"`
	NumSeguridadSocial string `xml:"numSeguridadSocial,attr,omitempty"`
	Importe            string `xml:"importe,attr"`
}

VDConcepto stores the data of a single food voucher

type ValesDeDespensa

type ValesDeDespensa struct {
	XMLName       xml.Name `xml:"valesdedespensa:ValesDeDespensa"`
	Version       string   `xml:"version,attr"`
	TipoOperacion string   `xml:"tipoOperacion,attr"`

	RegistroPatronal string `xml:"registroPatronal,attr,omitempty"`
	NumeroDeCuenta   string `xml:"numeroDeCuenta,attr"`
	Total            string `xml:"total,attr"`

	Conceptos []*VDConcepto `xml:"valesdedespensa:Conceptos>valesdedespensa:Concepto"` // nolint:misspell
}

ValesDeDespensa stores the food vouchers data

Directories

Path Synopsis
Package addendas adds additional functionality for "Addendas" to the CFDI documents.
Package addendas adds additional functionality for "Addendas" to the CFDI documents.
Package addon implements the CFDI (Comprobante Fiscal Digital por Internet) extensions and validation rules that need to be applied to GOBL documents in order to comply with the Mexican tax authority (SAT).
Package addon implements the CFDI (Comprobante Fiscal Digital por Internet) extensions and validation rules that need to be applied to GOBL documents in order to comply with the Mexican tax authority (SAT).
cmd
gobl.mx.cfdi command
Package main provides a CLI interface for the library
Package main provides a CLI interface for the library
Package internal contains additional functionality required internally.
Package internal contains additional functionality required internally.
format
Package format contains helps to help format output.
Package format contains helps to help format output.
Package test provides tools for testing the library
Package test provides tools for testing the library

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL