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