VerifactuMidAPI/verifactu/xml.go

293 lines
9.5 KiB
Go

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
}