// internal/models/models.go package models import ( "encoding/json" "encoding/xml" ) type FacturaElectronicaCompraVenta struct { XMLName xml.Name `xml:"facturaElectronicaCompraVenta"` Xsi string `xml:"xmlns:xsi,attr"` NoNamespaceSchemaLocation string `xml:"xsi:noNamespaceSchemaLocation,attr"` Cabecera Cabecera `xml:"cabecera"` Detalle []Detalle `xml:"detalle"` } type FacturaEventModel struct { TransaccionID string `json:"transaccion_id"` Estado string `json:"estado"` Payload RequestFacturacionModel `json:"payload"` } type RequestFacturacionModel struct { Cabecera Cabecera `json:"cabecera" xml:"cabecera"` Detalle []Detalle `json:"detalle" xml:"detalle"` } type Cabecera struct { NitEmisor int64 `json:"nitEmisor" xml:"nitEmisor"` RazonSocialEmisor string `json:"razonSocialEmisor" xml:"razonSocialEmisor"` Municipio string `json:"municipio" xml:"municipio"` Telefono Nullable[string] `json:"telefono" xml:"telefono"` NumeroFactura string `json:"numeroFactura" xml:"numeroFactura"` Cuf string `json:"cuf,omitempty" xml:"cuf,omitempty"` Cufd string `json:"cufd,omitempty" xml:"cufd,omitempty"` CodigoSucursal int `json:"codigoSucursal" xml:"codigoSucursal"` Direccion string `json:"direccion" xml:"direccion"` CodigoPuntoVenta Nullable[int] `json:"codigoPuntoVenta,omitempty" xml:"codigoPuntoVenta,omitempty"` FechaEmision string `json:"fechaEmision" xml:"fechaEmision"` NombreRazonSocial Nullable[string] `json:"nombreRazonSocial" xml:"nombreRazonSocial"` CodigoTipoDocumentoIdentidad int `json:"codigoTipoDocumentoIdentidad" xml:"codigoTipoDocumentoIdentidad"` NumeroDocumento string `json:"numeroDocumento" xml:"numeroDocumento"` Complemento Nullable[string] `json:"complemento,omitempty" xml:"complemento"` CodigoCliente string `json:"codigoCliente" xml:"codigoCliente"` CodigoMetodoPago int `json:"codigoMetodoPago" xml:"codigoMetodoPago"` NumeroTarjeta Nullable[string] `json:"numeroTarjeta,omitempty" xml:"numeroTarjeta"` MontoTotal float64 `json:"montoTotal" xml:"montoTotal"` MontoTotalSujetoIva float64 `json:"montoTotalSujetoIva" xml:"montoTotalSujetoIva"` CodigoMoneda int `json:"codigoMoneda" xml:"codigoMoneda"` TipoCambio float64 `json:"tipoCambio" xml:"tipoCambio"` MontoTotalMoneda float64 `json:"montoTotalMoneda" xml:"montoTotalMoneda"` MontoGiftCard Nullable[string] `json:"montoGiftCard" xml:"montoGiftCard"` DescuentoAdicional Nullable[float64] `json:"descuentoAdicional" xml:"descuentoAdicional"` CodigoExcepcion Nullable[int] `json:"codigoExcepcion,omitempty" xml:"codigoExcepcion,omitempty"` Cafc Nullable[string] `json:"cafc,omitempty" xml:"cafc"` Leyenda string `json:"leyenda" xml:"leyenda"` Usuario string `json:"usuario" xml:"usuario"` CodigoDocumentoSector int `json:"codigoDocumentoSector" xml:"codigoDocumentoSector"` TipoEmision int `json:"tipoEmision" xml:"-"` TipoFactura int `json:"tipoFactura" xml:"-"` } type Detalle struct { ActividadEconomica string `json:"actividadEconomica" xml:"actividadEconomica"` CodigoProductoSin int `json:"codigoProductoSin" xml:"codigoProductoSin"` CodigoProducto string `json:"codigoProducto" xml:"codigoProducto"` Descripcion string `json:"descripcion" xml:"descripcion"` Cantidad int `json:"cantidad" xml:"cantidad"` UnidadMedida int `json:"unidadMedida" xml:"unidadMedida"` PrecioUnitario float64 `json:"precioUnitario" xml:"precioUnitario"` MontoDescuento Nullable[float64] `json:"montoDescuento" xml:"montoDescuento"` SubTotal float64 `json:"subTotal" xml:"subTotal"` NumeroSerie Nullable[string] `json:"numeroSerie" xml:"numeroSerie"` NumeroImei Nullable[string] `json:"numeroImei" xml:"numeroImei"` } type Nullable[T any] struct { Value *T } // implementa la interfaz xml.Marshaler para cualquier tipo T func (n Nullable[T]) MarshalXML(e *xml.Encoder, start xml.StartElement) error { if n.Value == nil { // AƱadir el atributo xsi:nil="true" start.Attr = append(start.Attr, xml.Attr{ Name: xml.Name{Local: "xsi:nil"}, Value: "true", }) e.EncodeElement("", start) return nil } return e.EncodeElement(*n.Value, start) } // MarshalJSON implementa la interfaz json.Marshaler func (n Nullable[T]) MarshalJSON() ([]byte, error) { if n.Value == nil { return []byte("null"), nil } return json.Marshal(*n.Value) } // UnmarshalJSON implementa la interfaz json.Unmarshaler func (n *Nullable[T]) UnmarshalJSON(data []byte) error { // Si el valor es null, dejamos Value como nil if string(data) == "null" { n.Value = nil return nil } // Si no es null, intentamos deserializar en un valor de tipo T var value T if err := json.Unmarshal(data, &value); err != nil { return err } n.Value = &value return nil }