Skip to main content

Field Mapping: English (Invoice) ↔ Spanish (DTE JSON)

This document maps fields between the English Invoice interface (internal format) and the Spanish DteJson format (RPAfelApi format).

Architecture Overview

Current Approach: ✅ Recommended

  • Source of Truth: English Invoice interface (camelCase, flat structure)
  • Target Format: Spanish DteJson (PascalCase, nested structure)
  • Transformation: XmlToDteJsonService.convertInvoiceToDteJson()
  • When Used: When calling RPAfelApi provider

Field Mapping Reference

Root Level

English (Invoice)Spanish (DteJson)Notes
N/AID: "DatosCertificados"Constant value
N/ADatosEmisionWrapper object for all emission data
N/AextraContains subDomain and TipoEspecial

General Data

English PathSpanish PathTransformation
generalData.typeDatosEmision.DatosGenerales.TipoDirect mapping
generalData.dateTimeIssueDatosEmision.DatosGenerales.FechaHoraEmisionDirect mapping
generalData.currencyCodeDatosEmision.DatosGenerales.CodigoMonedaDefaults to "GTQ" if missing
addendumData.internalReferenceDatosEmision.DatosGenerales.rpaUUIDPassed as parameter
felProviderData.providerNameDatosEmision.DatosGenerales.rpaDE_EmpresaMapped via mapProviderName()
N/ADatosEmision.DatosGenerales.rpaCertificador_UsuarioSet from business config
N/ADatosEmision.DatosGenerales.rpaCertificador_ClaveSet from business config
N/ADatosEmision.DatosGenerales.rpaFisco_UsuarioEmpty string (default)

Issuer Data (Emisor)

English PathSpanish PathTransformation
issuerData.taxIdDatosEmision.Emisor.NITEmisorDirect mapping
issuerData.taxNameDatosEmision.Emisor.NombreEmisorDirect mapping
issuerData.establishmentCodeDatosEmision.Emisor.CodigoEstablecimientoDirect mapping
issuerData.commercialNameDatosEmision.Emisor.NombreComercialDirect mapping
issuerData.vatAffiliationCodeDatosEmision.Emisor.AfiliacionIVADirect mapping
issuerData.addressData.*DatosEmision.Emisor.DireccionEmisor.*See Address Mapping

Receiver Data (Receptor)

English PathSpanish PathTransformation
receiverData.taxNameDatosEmision.Receptor.NombreReceptorDirect mapping
receiverData.taxIdDatosEmision.Receptor.IDReceptorDirect mapping
receiverData.taxpayerTypeDatosEmision.Receptor.TipoEspecialDefaults to "NIT" if missing
receiverData.addressData.*DatosEmision.Receptor.DireccionReceptor.*See Address Mapping

Address Data

English PathSpanish PathTransformation
addressData.addressDireccionDirect mapping
addressData.postalCodeCodigoPostalDirect mapping
addressData.municipalityMunicipioDirect mapping
addressData.departmentDepartamentoDirect mapping
addressData.countryPaisDirect mapping

Phrases

English PathSpanish PathTransformation
phrases[]DatosEmision.Frases.Frase[]Array wrapped in object
phrases[].phraseTypeDatosEmision.Frases.Frase[].TipoFraseDirect mapping
phrases[].scenarioCodeDatosEmision.Frases.Frase[].CodigoEscenarioDirect mapping

Items

English PathSpanish PathTransformation
items[]DatosEmision.Items.Item[]Array wrapped in object
index + 1DatosEmision.Items.Item[].NumeroLineaLine number (1-based)
items[].goodOrServiceDatosEmision.Items.Item[].BienOServicioDirect mapping
items[].quantityDatosEmision.Items.Item[].CantidadConverted to string
items[].unitOfMeasureDatosEmision.Items.Item[].UnidadMedidaDirect mapping
items[].nameDatosEmision.Items.Item[].DescripcionDirect mapping
items[].unitPriceDatosEmision.Items.Item[].PrecioUnitarioConverted to string (2 decimals)
items[].amountDatosEmision.Items.Item[].PrecioConverted to string (2 decimals)
items[].discountDatosEmision.Items.Item[].DescuentoConverted to string (2 decimals)
items[].amount - items[].discountDatosEmision.Items.Item[].TotalCalculated, string (2 decimals)
items[].taxes[]DatosEmision.Items.Item[].Impuestos.Impuesto[]Array wrapped in object
items[].taxes[].shortNameDatosEmision.Items.Item[].Impuestos.Impuesto[].NombreCortoDirect mapping
items[].taxes[].taxableUnitCodeDatosEmision.Items.Item[].Impuestos.Impuesto[].CodigoUnidadGravableDirect mapping
items[].taxes[].taxableAmountDatosEmision.Items.Item[].Impuestos.Impuesto[].MontoGravableConverted to string (2 decimals)
items[].taxes[].taxAmountDatosEmision.Items.Item[].Impuestos.Impuesto[].MontoImpuestoConverted to string (2 decimals)

Totals

English PathSpanish PathTransformation
totalDatosEmision.Totales.GranTotalConverted to string (2 decimals)
Calculated from items[].taxes[]DatosEmision.Totales.TotalImpuestos.TotalImpuesto[]Aggregated by tax name
N/ADatosEmision.Totales.TotalImpuestos.TotalImpuesto[].NombreCortoTax name
N/ADatosEmision.Totales.TotalImpuestos.TotalImpuesto[].TotalMontoImpuestoSum of tax amounts (string, 2 decimals)

Extra Data

English PathSpanish PathTransformation
addendumData.versionextra.subDomainDirect mapping, defaults to ""
receiverData.taxpayerTypeextra.TipoEspecialOnly included if value is special type (CUI, EXT, etc.). NOT set for "NIT" (invalid value)

Fields NOT Mapped (English Only)

These fields exist in the English Invoice but are not included in the Spanish DTE JSON:

  • businessData.id - Used internally for business lookup, not sent to API
  • invoiceNumber - Optional field, not used in DTE JSON
  • date - Not included in DTE JSON structure
  • addendumData.dateReference - Not included in DTE JSON structure
  • addendumData.validateInternalReference - Not included in DTE JSON structure

Structural Differences

1. Nesting

  • English: Flat structure with top-level keys (generalData, issuerData, etc.)
  • Spanish: Nested under DatosEmision wrapper

2. Array Wrapping

  • English: Direct arrays (phrases[], items[])
  • Spanish: Arrays wrapped in objects (Frases.Frase[], Items.Item[])

3. Naming Convention

  • English: camelCase (dateTimeIssue, taxId)
  • Spanish: PascalCase (FechaHoraEmision, NITEmisor)

4. Data Types

  • English: Numbers and strings as-is
  • Spanish: Numbers converted to strings with 2 decimal places

Provider Name Mapping

English (providerName)Spanish (rpaDE_Empresa)
digifactDigifact
infileInfile
fegoraFegora
guatefacturaGuateFactura
rpafelapiDigifact (default fallback)

Usage Example

// English format (internal)
const invoice: Invoice = {
generalData: {
type: "FACT",
dateTimeIssue: "2025-10-21T22:13:59.079Z",
currencyCode: "GTQ"
},
// ... rest of invoice
};

// Convert to Spanish format (for API)
const dteJson = xmlToDteJsonService.convertInvoiceToDteJson(
invoice,
invoice.addendumData.internalReference
);

// Result: Spanish DTE JSON structure
// {
// ID: "DatosCertificados",
// DatosEmision: {
// DatosGenerales: {
// Tipo: "FACT",
// FechaHoraEmision: "2025-10-21T22:13:59.079Z",
// ...
// },
// ...
// }
// }

Best Practices

  1. ✅ Keep English as Source of Truth

    • Always create/update the English Invoice structure first
    • Transform to Spanish only when needed (API calls)
  2. ✅ Single Transformation Point

    • Use XmlToDteJsonService for all conversions
    • Don't create Spanish structure directly
  3. ✅ Type Safety

    • Use TypeScript interfaces (Invoice, DteJson)
    • Leverage type checking to catch mapping errors
  4. ✅ Maintainability

    • Update this document when fields change
    • Keep transformation logic centralized
  5. ✅ Testing

    • Test transformations with real data
    • Verify all fields are mapped correctly
    • Test edge cases (missing fields, null values)

Reverse Conversion (Spanish → English)

The service now includes convertDteJsonToInvoice() method for reverse conversion.

Reverse Field Mapping

Spanish PathEnglish PathTransformation
DatosEmision.DatosGenerales.TipogeneralData.typeDirect mapping
DatosEmision.DatosGenerales.FechaHoraEmisiongeneralData.dateTimeIssueDirect mapping
DatosEmision.DatosGenerales.CodigoMonedageneralData.currencyCodeDefaults to "GTQ" if missing
DatosEmision.DatosGenerales.rpaUUIDaddendumData.internalReferenceDirect mapping
DatosEmision.DatosGenerales.rpaDE_EmpresafelProviderData.providerNameReverse mapped via reverseMapProviderName()
DatosEmision.Emisor.NITEmisorissuerData.taxIdDirect mapping
DatosEmision.Emisor.NombreEmisorissuerData.taxNameDirect mapping
DatosEmision.Emisor.CodigoEstablecimientoissuerData.establishmentCodeDirect mapping
DatosEmision.Emisor.NombreComercialissuerData.commercialNameDirect mapping
DatosEmision.Emisor.AfiliacionIVAissuerData.vatAffiliationCodeDirect mapping
DatosEmision.Emisor.DireccionEmisor.*issuerData.addressData.*See Address Reverse Mapping
DatosEmision.Receptor.NombreReceptorreceiverData.taxNameDirect mapping
DatosEmision.Receptor.IDReceptorreceiverData.taxIdDirect mapping
DatosEmision.Receptor.TipoEspecial or extra.TipoEspecialreceiverData.taxpayerTypeDefaults to "NIT" if missing
DatosEmision.Receptor.DireccionReceptor.*receiverData.addressData.*See Address Reverse Mapping
DatosEmision.Frases.Frase[]phrases[]Unwrapped from object
DatosEmision.Frases.Frase[].TipoFrasephrases[].phraseTypeDirect mapping
DatosEmision.Frases.Frase[].CodigoEscenariophrases[].scenarioCodeDirect mapping
DatosEmision.Items.Item[]items[]Unwrapped from object
DatosEmision.Items.Item[].Descripcionitems[].nameDirect mapping
DatosEmision.Items.Item[].Cantidaditems[].quantityParsed to number
DatosEmision.Items.Item[].UnidadMedidaitems[].unitOfMeasureDirect mapping
DatosEmision.Items.Item[].PrecioUnitarioitems[].unitPriceParsed to number
DatosEmision.Items.Item[].Precioitems[].amountParsed to number
DatosEmision.Items.Item[].Descuentoitems[].discountParsed to number
DatosEmision.Items.Item[].BienOServicioitems[].goodOrServiceDirect mapping
DatosEmision.Items.Item[].Impuestos.Impuesto[]items[].taxes[]Unwrapped from object
DatosEmision.Items.Item[].Impuestos.Impuesto[].NombreCortoitems[].taxes[].shortNameDirect mapping
DatosEmision.Items.Item[].Impuestos.Impuesto[].CodigoUnidadGravableitems[].taxes[].taxableUnitCodeDirect mapping
DatosEmision.Items.Item[].Impuestos.Impuesto[].MontoGravableitems[].taxes[].taxableAmountParsed to number
DatosEmision.Items.Item[].Impuestos.Impuesto[].MontoImpuestoitems[].taxes[].taxAmountParsed to number
DatosEmision.Totales.GranTotaltotalParsed to number
extra.subDomainaddendumData.versionDirect mapping
DatosEmision.Referencias.Referencia[0].NumeroDocumentooriginalInvoiceUuidFor NCRE/NDEB/ANULACION
DatosEmision.Referencias.Referencia[0].MotivoAjusteadjustmentReasonFor NCRE/NDEB
DatosEmision.Referencias.Referencia[0].MotivoAnulacioncancellationReasonFor ANULACION
DatosEmision.Referencias.Referencia[0].FechaEmisionoriginalInvoiceDateFor ANULACION

Address Reverse Mapping

Spanish PathEnglish PathTransformation
DireccionaddressData.addressDirect mapping
CodigoPostaladdressData.postalCodeDirect mapping
MunicipioaddressData.municipalityDirect mapping
DepartamentoaddressData.departmentDirect mapping
PaisaddressData.countryDirect mapping

Reverse Provider Name Mapping

Spanish (rpaDE_Empresa)English (providerName)
Digifactdigifact
Infileinfile
Fegorafegora
GuateFacturaguatefactura
Other/Unknowndigifact (default)

Fields Lost in Reverse Conversion

These fields exist in English Invoice but are not present in Spanish DTE JSON, so they will be:

  • Set to default values
  • Derived from other fields
  • Or lost entirely
English FieldDefault/Derived Value
invoiceNumberNot available (lost)
dateDerived from FechaHoraEmision (date portion only)
addendumData.dateReferenceSet to FechaHoraEmision
addendumData.validateInternalReferenceSet to "VALIDAR" (default)
businessData.idMust be provided as parameter to convertDteJsonToInvoice()

Reverse Conversion Usage Example

// Spanish format (from API)
const dteJson: DteJson = {
ID: "DatosCertificados",
DatosEmision: {
DatosGenerales: {
Tipo: "FACT",
FechaHoraEmision: "2025-01-21T10:00:00.000Z",
...
},
...
}
};

// Convert back to English format (internal)
const invoice = xmlToDteJsonService.convertDteJsonToInvoice(
dteJson,
"business-123" // businessId must be provided
);

// Result: English Invoice structure
// {
// generalData: {
// type: "FACT",
// dateTimeIssue: "2025-01-21T10:00:00.000Z",
// ...
// },
// ...
// }

Reverse Conversion Notes

  1. Business ID Required: convertDteJsonToInvoice() requires businessId as a parameter since it's not in DTE JSON
  2. Data Type Conversion: String numbers are parsed back to numbers
  3. Array Unwrapping: Arrays wrapped in objects are unwrapped (e.g., Frases.Frase[]phrases[])
  4. Missing Fields: Missing optional fields default to empty strings or empty arrays
  5. Validation: Reverse conversion validates that DatosEmision and DatosGenerales exist

Last Updated: 2025-01-21 Maintained By: FEL Team