2026-04-08 12:31:05 +00:00
|
|
|
package verifactu
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"encoding/xml"
|
|
|
|
|
"fmt"
|
2026-04-17 11:03:06 +00:00
|
|
|
"time"
|
2026-04-08 12:31:05 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
type AltaRequest struct {
|
|
|
|
|
Cabecera Cabecera `xml:"sum:RegFactuSistemaFacturacion>sum:Cabecera"`
|
|
|
|
|
RegistroAlta RegistroAlta `xml:"sum:RegFactuSistemaFacturacion>sum:RegistroFactura>sum1:RegistroAlta"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Cabecera struct {
|
|
|
|
|
ObligadoEmision ObligadoEmision `xml:"sum1:ObligadoEmision"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type ObligadoEmision struct {
|
|
|
|
|
NombreRazon string `xml:"sum1:NombreRazon"`
|
|
|
|
|
NIF string `xml:"sum1:NIF"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type RegistroAlta struct {
|
|
|
|
|
IDVersion string `xml:"sum1:IDVersion"`
|
|
|
|
|
IDFactura IDFactura `xml:"sum1:IDFactura"`
|
|
|
|
|
NombreRazonEmisor string `xml:"sum1:NombreRazonEmisor"`
|
|
|
|
|
TipoFactura string `xml:"sum1:TipoFactura"`
|
|
|
|
|
DescripcionOperacion string `xml:"sum1:DescripcionOperacion"`
|
|
|
|
|
Desglose Desglose `xml:"sum1:Desglose"`
|
|
|
|
|
CuotaTotal string `xml:"sum1:CuotaTotal"`
|
|
|
|
|
ImporteTotal string `xml:"sum1:ImporteTotal"`
|
|
|
|
|
Encadenamiento Encadenamiento `xml:"sum1:Encadenamiento"`
|
|
|
|
|
SistemaInformatico SistemaInformatico `xml:"sum1:SistemaInformatico"`
|
|
|
|
|
FechaHoraHusoGenRegistro string `xml:"sum1:FechaHoraHusoGenRegistro"`
|
|
|
|
|
TipoHuella string `xml:"sum1:TipoHuella"`
|
|
|
|
|
Huella string `xml:"sum1:Huella"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type IDFactura struct {
|
|
|
|
|
IDEmisorFactura string `xml:"sum1:IDEmisorFactura"`
|
|
|
|
|
NumSerieFactura string `xml:"sum1:NumSerieFactura"`
|
|
|
|
|
FechaExpedicionFactura string `xml:"sum1:FechaExpedicionFactura"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Destinatarios struct {
|
|
|
|
|
IDDestinatario []IDDestinatario `xml:"sum1:IDDestinatario"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type IDDestinatario struct {
|
|
|
|
|
NombreRazon string `xml:"sum1:NombreRazon"`
|
|
|
|
|
NIF string `xml:"sum1:NIF"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Desglose struct {
|
|
|
|
|
DetalleDesglose []DetalleDesglose `xml:"sum1:DetalleDesglose"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type DetalleDesglose struct {
|
|
|
|
|
ClaveRegimen string `xml:"sum1:ClaveRegimen"`
|
|
|
|
|
CalificacionOperacion string `xml:"sum1:CalificacionOperacion"`
|
|
|
|
|
TipoImpositivo string `xml:"sum1:TipoImpositivo"`
|
|
|
|
|
BaseImponibleOimporteNoSujeto string `xml:"sum1:BaseImponibleOimporteNoSujeto"`
|
|
|
|
|
CuotaRepercutida string `xml:"sum1:CuotaRepercutida"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Encadenamiento struct {
|
|
|
|
|
PrimerRegistro string `xml:"sum1:PrimerRegistro,omitempty"`
|
|
|
|
|
RegistroAnterior *RegistroAnterior `xml:"sum1:RegistroAnterior,omitempty"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type RegistroAnterior struct {
|
|
|
|
|
IDEmisorFactura string `xml:"sum1:IDEmisorFactura"`
|
|
|
|
|
NumSerieFactura string `xml:"sum1:NumSerieFactura"`
|
|
|
|
|
FechaExpedicionFactura string `xml:"sum1:FechaExpedicionFactura"`
|
|
|
|
|
Huella string `xml:"sum1:Huella"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type SistemaInformatico struct {
|
|
|
|
|
NombreRazon string `xml:"sum1:NombreRazon"`
|
|
|
|
|
NIF string `xml:"sum1:NIF"`
|
|
|
|
|
NombreSistemaInformatico string `xml:"sum1:NombreSistemaInformatico"`
|
|
|
|
|
IdSistemaInformatico string `xml:"sum1:IdSistemaInformatico"`
|
|
|
|
|
Version string `xml:"sum1:Version"`
|
|
|
|
|
NumeroInstalacion string `xml:"sum1:NumeroInstalacion"`
|
|
|
|
|
TipoUsoPosibleSoloVerifactu string `xml:"sum1:TipoUsoPosibleSoloVerifactu"`
|
|
|
|
|
TipoUsoPosibleMultiOT string `xml:"sum1:TipoUsoPosibleMultiOT"`
|
|
|
|
|
IndicadorMultiplesOT string `xml:"sum1:IndicadorMultiplesOT"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type AnulacionRequest struct {
|
|
|
|
|
Cabecera Cabecera `xml:"sum:RegFactuSistemaFacturacion>sum:Cabecera"`
|
|
|
|
|
RegistroAnulacion RegistroAnulacion `xml:"sum:RegFactuSistemaFacturacion>sum:RegistroFactura>sum1:RegistroAnulacion"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type RegistroAnulacion struct {
|
|
|
|
|
IDVersion string `xml:"sum1:IDVersion"`
|
|
|
|
|
IDFacturaAnulada IDFacturaAnulada `xml:"sum1:IDFacturaAnulada"`
|
|
|
|
|
Encadenamiento Encadenamiento `xml:"sum1:Encadenamiento"`
|
|
|
|
|
SistemaInformatico SistemaInformatico `xml:"sum1:SistemaInformatico"`
|
|
|
|
|
FechaHoraHusoGenRegistro string `xml:"sum1:FechaHoraHusoGenRegistro"`
|
|
|
|
|
TipoHuella string `xml:"sum1:TipoHuella"`
|
|
|
|
|
Huella string `xml:"sum1:Huella"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type IDFacturaAnulada struct {
|
|
|
|
|
IDEmisorFacturaAnulada string `xml:"sum1:IDEmisorFacturaAnulada"`
|
|
|
|
|
NumSerieFacturaAnulada string `xml:"sum1:NumSerieFacturaAnulada"`
|
|
|
|
|
FechaExpedicionFacturaAnulada string `xml:"sum1:FechaExpedicionFacturaAnulada"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Response struct {
|
|
|
|
|
XMLName xml.Name `xml:"Envelope"`
|
|
|
|
|
Body ResponseBody
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type ResponseBody struct {
|
|
|
|
|
XMLName xml.Name `xml:"Body"`
|
|
|
|
|
Fault *Fault `xml:"Fault,omitempty"`
|
|
|
|
|
RegistroRespuesta *RegistroRespuesta `xml:"RegistroRespuesta,omitempty"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type Fault struct {
|
|
|
|
|
FaultCode string `xml:"faultcode"`
|
|
|
|
|
FaultString string `xml:"faultstring"`
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type RegistroRespuesta struct {
|
|
|
|
|
CSV string `xml:"CSV"`
|
|
|
|
|
Estado string `xml:"Estado"`
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-17 11:03:06 +00:00
|
|
|
type AltaData struct {
|
|
|
|
|
EmisorNombre string
|
|
|
|
|
EmisorNIF string
|
|
|
|
|
NumSerie string
|
|
|
|
|
FechaExpedicion time.Time
|
|
|
|
|
TipoFactura string
|
|
|
|
|
Descripcion string
|
|
|
|
|
DestinatarioNombre string
|
|
|
|
|
DestinatarioNIF string
|
|
|
|
|
IVA []IVARegularizacionData
|
|
|
|
|
CuotaTotal float64
|
|
|
|
|
ImporteTotal float64
|
|
|
|
|
Sistema SistemaData
|
|
|
|
|
Huella string
|
|
|
|
|
FechaGen time.Time
|
|
|
|
|
PrevHash string
|
2026-04-08 12:31:05 +00:00
|
|
|
}
|
|
|
|
|
|
2026-04-17 11:03:06 +00:00
|
|
|
type IVARegularizacionData struct {
|
|
|
|
|
Base float64
|
|
|
|
|
Cuota float64
|
|
|
|
|
Tipo float64
|
|
|
|
|
ClaveRegimen string
|
|
|
|
|
Calificacion string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type SistemaData struct {
|
|
|
|
|
Nombre string
|
|
|
|
|
NIFProveedor string
|
|
|
|
|
NombreSistema string
|
|
|
|
|
Version string
|
|
|
|
|
NumeroInstalacion string
|
|
|
|
|
TipoUsoVerifactu string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func BuildAltaRequest(data AltaData) *AltaRequest {
|
|
|
|
|
fechaExp := data.FechaExpedicion.Format("02-01-2006")
|
|
|
|
|
fechaGen := data.FechaGen.Format("02-01-2006T15:04:05")
|
|
|
|
|
|
|
|
|
|
ivaList := make([]DetalleDesglose, len(data.IVA))
|
|
|
|
|
for i, iva := range data.IVA {
|
|
|
|
|
ivaList[i] = DetalleDesglose{
|
|
|
|
|
ClaveRegimen: iva.ClaveRegimen,
|
|
|
|
|
CalificacionOperacion: iva.Calificacion,
|
|
|
|
|
TipoImpositivo: fmt.Sprintf("%.2f", iva.Tipo),
|
|
|
|
|
BaseImponibleOimporteNoSujeto: fmt.Sprintf("%.2f", iva.Base),
|
|
|
|
|
CuotaRepercutida: fmt.Sprintf("%.2f", iva.Cuota),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var enc Encadenamiento
|
|
|
|
|
if data.PrevHash == "" {
|
|
|
|
|
enc = Encadenamiento{PrimerRegistro: "S"}
|
|
|
|
|
} else {
|
|
|
|
|
enc = Encadenamiento{
|
|
|
|
|
PrimerRegistro: "N",
|
|
|
|
|
RegistroAnterior: &RegistroAnterior{
|
|
|
|
|
IDEmisorFactura: data.EmisorNIF,
|
|
|
|
|
NumSerieFactura: data.NumSerie,
|
|
|
|
|
FechaExpedicionFactura: fechaExp,
|
|
|
|
|
Huella: data.PrevHash,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
req := &AltaRequest{
|
|
|
|
|
Cabecera: Cabecera{
|
|
|
|
|
ObligadoEmision: ObligadoEmision{
|
|
|
|
|
NombreRazon: data.EmisorNombre,
|
|
|
|
|
NIF: data.EmisorNIF,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
RegistroAlta: RegistroAlta{
|
|
|
|
|
IDVersion: "1.0",
|
|
|
|
|
IDFactura: IDFactura{
|
|
|
|
|
IDEmisorFactura: data.EmisorNIF,
|
|
|
|
|
NumSerieFactura: data.NumSerie,
|
|
|
|
|
FechaExpedicionFactura: fechaExp,
|
|
|
|
|
},
|
|
|
|
|
NombreRazonEmisor: data.EmisorNombre,
|
|
|
|
|
TipoFactura: data.TipoFactura,
|
|
|
|
|
DescripcionOperacion: data.Descripcion,
|
|
|
|
|
Desglose: Desglose{
|
|
|
|
|
DetalleDesglose: ivaList,
|
|
|
|
|
},
|
|
|
|
|
CuotaTotal: fmt.Sprintf("%.2f", data.CuotaTotal),
|
|
|
|
|
ImporteTotal: fmt.Sprintf("%.2f", data.ImporteTotal),
|
|
|
|
|
Encadenamiento: enc,
|
|
|
|
|
SistemaInformatico: SistemaInformatico{
|
|
|
|
|
NombreRazon: data.Sistema.Nombre,
|
|
|
|
|
NIF: data.Sistema.NIFProveedor,
|
|
|
|
|
NombreSistemaInformatico: data.Sistema.NombreSistema,
|
|
|
|
|
IdSistemaInformatico: "1",
|
|
|
|
|
Version: data.Sistema.Version,
|
|
|
|
|
NumeroInstalacion: data.Sistema.NumeroInstalacion,
|
|
|
|
|
TipoUsoPosibleSoloVerifactu: data.Sistema.TipoUsoVerifactu,
|
|
|
|
|
TipoUsoPosibleMultiOT: "N",
|
|
|
|
|
IndicadorMultiplesOT: "N",
|
|
|
|
|
},
|
|
|
|
|
FechaHoraHusoGenRegistro: fechaGen,
|
|
|
|
|
TipoHuella: "SHA-256",
|
|
|
|
|
Huella: data.Huella,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return req
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func BuildAnulacionRequest(data AltaData) *AnulacionRequest {
|
|
|
|
|
fechaExp := data.FechaExpedicion.Format("02-01-2006")
|
|
|
|
|
fechaGen := data.FechaGen.Format("02-01-2006T15:04:05")
|
|
|
|
|
|
|
|
|
|
var enc Encadenamiento
|
|
|
|
|
if data.PrevHash == "" {
|
|
|
|
|
enc = Encadenamiento{PrimerRegistro: "S"}
|
|
|
|
|
} else {
|
|
|
|
|
enc = Encadenamiento{
|
|
|
|
|
PrimerRegistro: "N",
|
|
|
|
|
RegistroAnterior: &RegistroAnterior{
|
|
|
|
|
IDEmisorFactura: data.EmisorNIF,
|
|
|
|
|
NumSerieFactura: data.NumSerie,
|
|
|
|
|
FechaExpedicionFactura: fechaExp,
|
|
|
|
|
Huella: data.PrevHash,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
req := &AnulacionRequest{
|
|
|
|
|
Cabecera: Cabecera{
|
|
|
|
|
ObligadoEmision: ObligadoEmision{
|
|
|
|
|
NombreRazon: data.EmisorNombre,
|
|
|
|
|
NIF: data.EmisorNIF,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
RegistroAnulacion: RegistroAnulacion{
|
|
|
|
|
IDVersion: "1.0",
|
|
|
|
|
IDFacturaAnulada: IDFacturaAnulada{
|
|
|
|
|
IDEmisorFacturaAnulada: data.EmisorNIF,
|
|
|
|
|
NumSerieFacturaAnulada: data.NumSerie,
|
|
|
|
|
FechaExpedicionFacturaAnulada: fechaExp,
|
|
|
|
|
},
|
|
|
|
|
Encadenamiento: enc,
|
|
|
|
|
SistemaInformatico: SistemaInformatico{
|
|
|
|
|
NombreRazon: data.Sistema.Nombre,
|
|
|
|
|
NIF: data.Sistema.NIFProveedor,
|
|
|
|
|
NombreSistemaInformatico: data.Sistema.NombreSistema,
|
|
|
|
|
IdSistemaInformatico: "1",
|
|
|
|
|
Version: data.Sistema.Version,
|
|
|
|
|
NumeroInstalacion: data.Sistema.NumeroInstalacion,
|
|
|
|
|
TipoUsoPosibleSoloVerifactu: data.Sistema.TipoUsoVerifactu,
|
|
|
|
|
TipoUsoPosibleMultiOT: "N",
|
|
|
|
|
IndicadorMultiplesOT: "N",
|
|
|
|
|
},
|
|
|
|
|
FechaHoraHusoGenRegistro: fechaGen,
|
|
|
|
|
TipoHuella: "SHA-256",
|
|
|
|
|
Huella: data.Huella,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return req
|
2026-04-08 12:31:05 +00:00
|
|
|
}
|