package verifactu import ( "encoding/xml" "fmt" "time" ) 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"` } 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 } 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 }