Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Errores (relacionados con al AEAT) (https://www.clubdelphi.com/foros/forumdisplay.php?f=78)
-   -   Error FechaHoraHusoGenRegistro al enviar factura (https://www.clubdelphi.com/foros/showthread.php?t=97445)

rci 16-04-2025 12:38:08

FechaHoraHusoGenRegistro y configuración de la zona horaria PC
 
Hola, nosotros trabajamos en c#, importamos el wsdl y este genera unas clases con los objetos y sus propiedades.
Para crear un registro de facturación, creamos un objeto y lo rellenamos.
Para enviar ese registro, creamos otro objeto con todos los registros de facturación a enviar y lo enviamos directamente con las funciones que se generaron al importar el wsdl, pasándole el objeto para enviar.
No creamos el XML a pelo, de hecho no haría falta serializar el objeto a XML, si no fuera para guardarlo (en fichero o en base de datos).

Esto ya nos funciona pero hemos encontrado un caso que no funciona correctamente.

El tema está en el campo FechaHoraHusoGenRegistro, al importar el wsdl ese campo se crea como un DateTime.
En la documentación ese campo es una fecha en formato YYYY-MM-DDThh:mm:ssTZD (ej: 2024-01-01T19:20:30+01:00) (ISO 8601)
Al rellenar la propiedad en el objeto le indicamos que ese DateTime tiene DateTimeKind.Local para indicar que la hora representada es la hora local.
Para calcular la huella necesitamos esa fecha en formato de cadena y lo convertimos de forma que aparezca la información de la zona horaria.

Hemos visto que estas dos operaciones, utilizan la configuración de la zona horaria del ordenador donde se ejecuta.

Hasta aquí todo bien. En condiciones normales funciona perfectamente.

El problema lo tenemos cuando hay un ordenador con una configuración de zona horaria y otro con otra configuración.
Hemos visto que si el registro de facturación lo genera y lo envía el mismo ordenador, no hay problema.
Pero si el registro de facturación lo genera un ordenador y lo envía otro (con configuración de zona horaria distinta) luego la factura es aceptada con errores y el error es de la huella.
2000 El cálculo de la huella suministrada es incorrecta.

Puntualizar que en nuestro caso cada ordenador genera registros de facturación, se guardan en una BD central de un servidor, y en ese servidor hay un servicio que va enviando los RFs.

Imaginamos que el error ocurre porque el tipo de datos DateTime de c# no tiene información del desplazamiento respecto UTC y mira la configuración de zona horaria del ordenador donde se ejecuta. Pensamos que la función para enviar el objeto, también utiliza esa configuración y depende del ordenador envía una cosa u otra.
Por ejemplo desde un ordenador envía 2025-04-15T15:57:46+01:00 desde el otro envía 2025-04-15T15:57:46+02:00
Y claro cuando hacienda hace las validaciones y genera la huella, si la FechaHoraHusoGenRegistro no es la correcta, la huella cambia.

Hemos estado haciendo varias pruebas y buscando varias posibilidades pero no hemos encontrado la forma de solucionarlo.

Pensamos que tenemos varias opciones:

1. No permitir que varios ordenadores tengan distintas configuraciones de zona horaria.

2. Modificar las clases que se generan al importar el wsdl, cambiar el tipo del campo FechaHoraHusoGenRegistro para que sea una cadena y hacer el tratamiento nosotros del valor de la zona horaria

3. Para el envió, no trabajar con los objetos, sino utilizar una cadena con el XML y enviar ese string directamente haciendo un POST. (y controlar el valor de la zona horaria del campo).

Seguramente haremos la opción 1, no se si algún cliente nuestro requerirá configuraciones distintas.
Sobre la opción 2, no nos gusta demasiado porque cada vez que se actualice el wsdl se tendrá que volver a cambiar.
Sobre la opción 3, pensamos que en general es mejor para nosotros trabajar con los objetos, para rellenarlos y para tratar las respuestas obtenidas.

No se si alguno de vosotros trabaja en c# y se ha encontrado con este problema o si tenéis alguna otra idea para afrontar ese caso.

Muchas gracias

rci 16-04-2025 14:03:22

nueva prueba
 
Hola, hemos seguido investigando y haciendo pruebas y tenemos otra opción, pero no tenemos claro que sea correcta.

Lo que hemos hecho ahora es al rellenar la propiedad de la fecha hora de generación, en el objeto le indicamos que ese DateTime tiene DateTimeKind.Utc para indicar que la hora representada es la hora UTC.
Para calcular la huella ahora la cadena para representar FechaHoraHusoGenRegistro en formato ISO 8601 no tiene un +01:00 al final sino que tiene una Z.

Luego tanto si envío ese registro de facturación desde un ordenador como desde otro con una configuración de zona horaria (huso) distinta, se envía el mismo valor y las facturas son aceptadas sin errores.

Pero tenemos la duda sobre si la hora de generación que estamos informando es la correcta.
Consultando por la web los datos de las facturas ya enviadas, tenemos
Fecha de presentación: 16-04-2025 13:28:49
Fecha de generación del registro: 2025-04-16T12:24:36Z


Estamos indicando la misma fecha y hora en los dos campos? (Los minutos y segundos varían un poco por el tiempo que he tardado entre generar el registro y enviar pero eso no me importa para este tema, solo la hora)

Preguntando a la IA me ha contestado lo siguiente:
Cita:

Cuando la fecha se marca como DateTimeKind.Utc, se establece que el valor se interpretará y se serializará en tiempo universal coordinado (UTC). Así, una fecha como 2025-04-16T12:24:36Z significa que realmente es las 12:24:36 en UTC.

Si tu otra referencia indica que la fecha de presentación es 16-04-2025 13:24:36 y esa fecha está en hora local con una configuración de huso horario de UTC+1 (como es típico en muchas zonas de Europa durante el horario estándar), entonces 12:24:36 UTC equivalen exactamente a 13:24:36.

Por tanto, aunque las cadenas de texto son diferentes (una con la "Z" y la otra con un formato local sin indicación explícita de offset), ambas representan el mismo instante en el tiempo. Este comportamiento es por lo que se espera: la fecha con el sufijo "Z" es una representación estándar para indicar que el valor está en UTC, mientras que la fecha en formato local refleja el ajuste según la configuración hora del sistema.
Me ha parecido una explicación bastante lógica pero no se si fiarme mucho.
Como podéis ver no domino demasiado en temas de horas y husos horarios pero podría ser que sea correcto lo que me ha dicho.

Por otra parte AEAT ha contestado como correcta pero no se si es que no lo valida o que.
En la definición del campo FechaHoraHusoGenRegistro a parte de indicar el formato, también dice:
Cita:

Fecha, hora y huso horario de generación del registro de facturación. El huso horario es el que está usando el sistema informático de facturación en el momento de generación del registro de facturación.
No se yo si enviando una Z en lugar de +01:00 (o el que toque), estoy indicando bien el huso horario o no seria lo correcto....

En algún otro post de este foro he visto alguien que también enviaba una Z en FechaHoraHusoGenRegistro pero no encuentro el mensaje ni se si es correcto.

Vosotros que pensáis?

Muchas gracias!!

gcqZW 16-04-2025 14:39:54

las dos son las mismas fechashoras, lo que no indicas el huso horario, Z entiendo que es por hora "Zulú" que es la hora sin ningún huso horario (o +0), por lo que entiendo que se las traga ahora pero si quieren que le pasemos el huso horario te dará problemas en el futuro entiendo.

rci 16-04-2025 15:19:20

Cita:

Empezado por gcqZW (Mensaje 563840)
las dos son las mismas fechashoras, lo que no indicas el huso horario, Z entiendo que es por hora "Zulú" que es la hora sin ningún huso horario (o +0), por lo que entiendo que se las traga ahora pero si quieren que le pasemos el huso horario te dará problemas en el futuro entiendo.

Gracias gcqZW por la respuesta. podría ser:(

Neftali [Germán.Estévez] 16-04-2025 15:30:50

Cita:

Empezado por rci (Mensaje 563835)
...
El problema lo tenemos cuando hay un ordenador con una configuración de zona horaria y otro con otra configuración.

En nuestro caso, que también trabajamos con un servidor (SQLServer y donde están los servicios de envío), tenemos una función que nos devuelve la fecha/hora del Servidor (SQLSerevr).
En algunos casos (no en todos) no cogemos la hora del equipo, sino la del servidor (para el tema de Ley antifraude lo hemos usado en varios sitios).

rci 16-04-2025 15:46:57

Cita:

Empezado por Neftali [Germán.Estévez] (Mensaje 563846)
En nuestro caso, que también trabajamos con un servidor (SQLServer y donde están los servicios de envío), tenemos una función que nos devuelve la fecha/hora del Servidor (SQLSerevr).
En algunos casos (no en todos) no cogemos la hora del equipo, sino la del servidor (para el tema de Ley antifraude lo hemos usado en varios sitios).

Muchas gracias Neftali.
Nosotros también usamos la fecha y hora del servidor SQL server, y procuramos que ese servidor siempre esté en la hora exacta. No usamos la hora local del ordenador porque pueden estar fuera de hora y tampoco consultamos la hora de internet (ROA) a cada factura para evitar tantas consultas.
Pero independientemente de esto, nos ocurre lo mencionado en el primer post. Porque esa fecha hora del servidor SQL, al pasarla a DateTime, no tiene el huso y luego depende de donde se utilice ese DateTime, genera una FechaHoraHusoGenRegistro distinta.

Para coger la hora del servidor SQL primero usábamos la consulta
Código SQL [-]
SELECT GETDATE()
Pero solo devuelve un DateTime (sin huso)
Luego probamos con la consulta
Código SQL [-]
SELECT SYSDATETIMEOFFSET()
Que devuelve un DateTimeOffset, este tipo si que tiene una propiedad Offset con el desplazamiento de la hora respecto de la hora universal coordinada (UTC).

Esto seria fantástico si en la clase de VeriFactu que se genera al importar el WSDL, el objeto FechaHoraHusoGenRegistro fuera DateTimeOffset, pero no lo es.
Y estamos con el mismo problema

Muchas gracias

Jarogo08 16-04-2025 16:49:21

Cita:

Empezado por rci (Mensaje 563847)
SELECT SYSDATETIMEOFFSET()

Que devuelve un DateTimeOffset, este tipo si que tiene una propiedad Offset con el desplazamiento de la hora respecto de la hora universal coordinada (UTC).

Esto seria fantástico si en la clase de VeriFactu que se genera al importar el WSDL, el objeto FechaHoraHusoGenRegistro fuera DateTimeOffset, pero no lo es.
Y estamos con el mismo problema


¿y no puedes crear una función en el Visual que te devuelva un string, con el formato que necesita Verifactu?

si haciendo el "SYSDATETIMEOFFSET" obtienes algo como esto: "2025-04-16 16:44:01.6718891 +02:00"

y Verifactu necesita algo como esto: "2025-04-16T16:44:01+02:00"

entiendo que no sería difícil crear una función que haga la consulta, la ponga en el formato de Verifactu y la devuelva como string.

Y si la haces y la pones aquí, ya la aprovecho yo :D:D

Jarogo08 16-04-2025 17:15:29

Venga... ya la hice yo, la pongo aquí que mañana es festivo y estoy de buenas ;)

Código:

Function ObtenerFechaHora() As String
        Dim retorno As String = ""

        '-------------------------------------------
        '1 - COGEMOS LA HORA DE INTERNET
        '-------------------------------------------

        Try
            ServicePointManager.SecurityProtocol = CType(3072, SecurityProtocolType)    'TLS 1.2

            Dim webRequest As HttpWebRequest = CType(Net.WebRequest.Create("https://www2.roa.es/cgi-bin/horautc"), HttpWebRequest)
            webRequest.Method = "GET"
            Dim respuesta As HttpWebResponse = CType(webRequest.GetResponse(), HttpWebResponse)

            If respuesta.StatusCode = HttpStatusCode.OK Then
                Dim strmRespuesta As Stream = respuesta.GetResponseStream()
                Dim leeRespuesta As New StreamReader(strmRespuesta)
                Dim jsonRespuesta As String = leeRespuesta.ReadToEnd()
                Dim ticks As Long = Long.Parse(jsonRespuesta.Replace("\n", ""))
                Dim fechora As DateTime = Org.BouncyCastle.Utilities.Date.DateTimeUtilities.UnixMsToDateTime(ticks).ToLocalTime()
                retorno = fechora.ToString("yyyy-MM-dd'T'HH:mm:ssK")
            End If

        Catch Ex As Exception
            'MsgBox(Ex.Message, MsgBoxStyle.OkOnly, "ObtenerFechaHora - Internet")
        End Try


        '-------------------------------------------
        '2 - COGEMOS LA HORA DEL SERVIDOR SQL
        '-------------------------------------------

        If retorno = "" Then
            Try
                Dim DAHora As New SqlDataAdapter
                Dim DSHora As New DataSet
                Dim SqlHora As String = "SELECT SYSDATETIMEOFFSET() AS FechaActual"
                DSHora.Reset()
                DAHora = New SqlDataAdapter(SqlHora, Conexion)
                DAHora.Fill(DSHora, "Hora")

                If DSHora.Tables("Hora").Rows.Count = 1 Then
                    Dim RowHora As DataRow = DSHora.Tables("Hora").Rows(0)

                    Dim fechora As DateTime = RowHora.Item("FechaActual").ToString
                    retorno = fechora.ToString("yyyy-MM-dd'T'HH:mm:ssK")
                End If

                DAHora.Dispose()
                DSHora.Dispose()

            Catch Ex As Exception
                'MsgBox(Ex.Message, MsgBoxStyle.OkOnly, "ObtenerFechaHora - Servidor")
            End Try
        End If


        '-------------------------------------------
        '2 - COGEMOS LA HORA DEL EQUIPO
        '-------------------------------------------

        If retorno = "" Then
            retorno = DateTime.Now.ToString("yyyy-MM-dd'T'HH:mm:ssK")
        End If

        Return retorno
    End Function


Primero intenta cogerla de internet, si no es capaz del servidor sql y si no es capaz del equipo

La primera puede dar error si no hay internet o no responde ROA... la segunda debería devolver siempre (si no hay conexión al servidor ya no va a funcionar la aplicación)

Espero que te sirva!

rci 16-04-2025 17:21:39

Cita:

Empezado por Jarogo08 (Mensaje 563849)
¿y no puedes crear una función en el Visual que te devuelva un string, con el formato que necesita Verifactu?

si haciendo el "SYSDATETIMEOFFSET" obtienes algo como esto: "2025-04-16 16:44:01.6718891 +02:00"

y Verifactu necesita algo como esto: "2025-04-16T16:44:01+02:00"

entiendo que no sería difícil crear una función que haga la consulta, la ponga en el formato de Verifactu y la devuelva como string.

Hola Jarogo08, este no es exactamente el problema.
Si utilizo un string para almacenar la FechaHoraHusoGenRegistro al generar el registro, ya se guarda correctamente PERO, con las clases que se genera en Visual Studio al importar el WSDL, el campo no es string sino DateTime.

Para utilizar ese string tendría que hacer una de las opciones 2 o 3 que comento en el primer post y que intento evitar :)

Muchas gracias igualmente

Jarogo08 16-04-2025 17:26:52

Cita:

Empezado por rci (Mensaje 563851)
Si utilizo un string para almacenar la FechaHoraHusoGenRegistro al generar el registro, ya se guarda correctamente PERO, con las clases que se genera en Visual Studio al importar el WSDL, el campo no es string sino DateTime.


pues a mi usando el objeto me deja asignarle un campo string:

Código:

CType(objectoFactEmitida.RegistroFactura(x).Item, RegistroFacturacionAltaType).FechaHoraHusoGenRegistro = Row.Item("FechaHoraHusoGenRegistro")
CType(objectoFactEmitida.RegistroFactura(x).Item, RegistroFacturacionAltaType).TipoHuella = TipoHuellaType.Item01
CType(objectoFactEmitida.RegistroFactura(x).Item, RegistroFacturacionAltaType).Huella = Row.Item("HuellaVerifactu")

donde "FechaHoraHusoGenRegistro" es un varchar(50) en la tabla del SQL Server

rci 16-04-2025 17:52:30

Cita:

Empezado por Jarogo08 (Mensaje 563852)
pues a mi usando el objeto me deja asignarle un campo string:

Código:

CType(objectoFactEmitida.RegistroFactura(x).Item, RegistroFacturacionAltaType).FechaHoraHusoGenRegistro = Row.Item("FechaHoraHusoGenRegistro")
CType(objectoFactEmitida.RegistroFactura(x).Item, RegistroFacturacionAltaType).TipoHuella = TipoHuellaType.Item01
CType(objectoFactEmitida.RegistroFactura(x).Item, RegistroFacturacionAltaType).Huella = Row.Item("HuellaVerifactu")

donde "FechaHoraHusoGenRegistro" es un varchar(50) en la tabla del SQL Server

Supongo que en tu caso, la propiedad FechaHoraHusoGenRegistro del objeto RegistroFacturacionAltaType es de tipo string y lo permite.
En nuestro caso es DateTime y no puedo hacer esa asignación directa sin convertir.

Al importar el WSDL dentro del fichero reference.cs genera el campo así:
Código:

    /// <remarks/>
    [System.Xml.Serialization.XmlElementAttribute(Order=25)]
    public System.DateTime FechaHoraHusoGenRegistro {
        get {
            return this.fechaHoraHusoGenRegistroField;
        }
        set {
            this.fechaHoraHusoGenRegistroField = value;
            this.RaisePropertyChanged("FechaHoraHusoGenRegistro");
        }
    }

y dentro del fichero SuministroInformacion.xsd también indica dateTime

Código:

<element name="FechaHoraHusoGenRegistro" type="dateTime" />

Gracias igualmente

Jarogo08 16-04-2025 18:17:00

a mi también me dice que es de tipo Date. Entiendo que a todo el mundo debería decirle lo mismo, porque estamos importando el mismo wsdl:


Código:

        '''<remarks/>
        Public Property FechaHoraHusoGenRegistro() As Date
            Get
                Return Me.fechaHoraHusoGenRegistroField
            End Get
            Set
                Me.fechaHoraHusoGenRegistroField = value
            End Set
        End Property


pero me traga cuando lo que le envío es un string:
Código:

CType(objectoFactEmitida.RegistroFactura(x).Item, RegistroFacturacionAnulacionType).FechaHoraHusoGenRegistro = Row.Item("FechaHoraHusoGenRegistro")
no sé a que puede ser debido, pero te facilitaría mucho si te dejara!

rci 16-04-2025 18:19:56

Cita:

Empezado por Jarogo08 (Mensaje 563854)
a mi también me dice que es de tipo Date. Entiendo que a todo el mundo debería decirle lo mismo, porque estamos importando el mismo wsdl:


Código:

        '''<remarks/>
        Public Property FechaHoraHusoGenRegistro() As Date
            Get
                Return Me.fechaHoraHusoGenRegistroField
            End Get
            Set
                Me.fechaHoraHusoGenRegistroField = value
            End Set
        End Property


pero me traga cuando lo que le envío es un string:
Código:

CType(objectoFactEmitida.RegistroFactura(x).Item, RegistroFacturacionAnulacionType).FechaHoraHusoGenRegistro = Row.Item("FechaHoraHusoGenRegistro")
no sé a que puede ser debido, pero te facilitaría mucho si te dejara!

Pues sí :)

Imagino que Visual Basic lo trata diferente que C#:confused:

De todas formas también afecta a la hora de enviar. Si el objeto es DateTime, no tiene información del huso horario y coge la configuración del ordenador que envía, y aquí viene el problema si no es la misma que el ordenador que generó el registro de facturación.

Gracias

bmfranky 16-04-2025 19:50:36

Fechaora internet con uso horadio
 
Hola @rci, Prueba esto.


public System.DateTime(System.DateTime currentDateTime)
{
return new DateTime(currentDateTime.Year, currentDateTime.Month, currentDateTime.Day, currentDateTime.Hour, currentDateTime.Minute, currentDateTime.Second, DateTimeKind.Local);
}
Si la hora no es local la convierte a local.

bmfranky 16-04-2025 20:32:56

Cita:

Empezado por rci (Mensaje 563835)
Hola, nosotros trabajamos en c#, importamos el wsdl y este genera unas clases con los objetos y sus propiedades.
Para crear un registro de facturación, creamos un objeto y lo rellenamos.
Para enviar ese registro, creamos otro objeto con todos los registros de facturación a enviar y lo enviamos directamente con las funciones que se generaron al importar el wsdl, pasándole el objeto para enviar.
No creamos el XML a pelo, de hecho no haría falta serializar el objeto a XML, si no fuera para guardarlo (en fichero o en base de datos).

Esto ya nos funciona pero hemos encontrado un caso que no funciona correctamente.

El tema está en el campo FechaHoraHusoGenRegistro, al importar el wsdl ese campo se crea como un DateTime.
En la documentación ese campo es una fecha en formato YYYY-MM-DDThh:mm:ssTZD (ej: 2024-01-01T19:20:30+01:00) (ISO 8601)
Al rellenar la propiedad en el objeto le indicamos que ese DateTime tiene DateTimeKind.Local para indicar que la hora representada es la hora local.
Para calcular la huella necesitamos esa fecha en formato de cadena y lo convertimos de forma que aparezca la información de la zona horaria.

Hemos visto que estas dos operaciones, utilizan la configuración de la zona horaria del ordenador donde se ejecuta.

Hasta aquí todo bien. En condiciones normales funciona perfectamente.

El problema lo tenemos cuando hay un ordenador con una configuración de zona horaria y otro con otra configuración.
Hemos visto que si el registro de facturación lo genera y lo envía el mismo ordenador, no hay problema.
Pero si el registro de facturación lo genera un ordenador y lo envía otro (con configuración de zona horaria distinta) luego la factura es aceptada con errores y el error es de la huella.
2000 El cálculo de la huella suministrada es incorrecta.

Puntualizar que en nuestro caso cada ordenador genera registros de facturación, se guardan en una BD central de un servidor, y en ese servidor hay un servicio que va enviando los RFs.

Imaginamos que el error ocurre porque el tipo de datos DateTime de c# no tiene información del desplazamiento respecto UTC y mira la configuración de zona horaria del ordenador donde se ejecuta. Pensamos que la función para enviar el objeto, también utiliza esa configuración y depende del ordenador envía una cosa u otra.
Por ejemplo desde un ordenador envía 2025-04-15T15:57:46+01:00 desde el otro envía 2025-04-15T15:57:46+02:00
Y claro cuando hacienda hace las validaciones y genera la huella, si la FechaHoraHusoGenRegistro no es la correcta, la huella cambia.

Hemos estado haciendo varias pruebas y buscando varias posibilidades pero no hemos encontrado la forma de solucionarlo.

Pensamos que tenemos varias opciones:

1. No permitir que varios ordenadores tengan distintas configuraciones de zona horaria.

2. Modificar las clases que se generan al importar el wsdl, cambiar el tipo del campo FechaHoraHusoGenRegistro para que sea una cadena y hacer el tratamiento nosotros del valor de la zona horaria

3. Para el envió, no trabajar con los objetos, sino utilizar una cadena con el XML y enviar ese string directamente haciendo un POST. (y controlar el valor de la zona horaria del campo).

Seguramente haremos la opción 1, no se si algún cliente nuestro requerirá configuraciones distintas.
Sobre la opción 2, no nos gusta demasiado porque cada vez que se actualice el wsdl se tendrá que volver a cambiar.
Sobre la opción 3, pensamos que en general es mejor para nosotros trabajar con los objetos, para rellenarlos y para tratar las respuestas obtenidas.

No se si alguno de vosotros trabaja en c# y se ha encontrado con este problema o si tenéis alguna otra idea para afrontar ese caso.

Muchas gracias

Hola, habeis probado a pasar el Date, como un parametro al mismo tiempo que enviais el registro y usarlo para generar la huella, asi seguro que es el mismo....

Osea que consultais la fecha hora al ordenador que hace el envio y la usais para generar el registro y la huella, asi seguro que es la misma, con unos segundos de diferencia.
El ordenador que hace el envio a su vez la consulta con la base de datos o internet o lo que sea.

rci 17-04-2025 09:09:28

Cita:

Empezado por bmfranky (Mensaje 563857)
Hola @rci, Prueba esto.


public System.DateTime(System.DateTime currentDateTime)
{
return new DateTime(currentDateTime.Year, currentDateTime.Month, currentDateTime.Day, currentDateTime.Hour, currentDateTime.Minute, currentDateTime.Second, DateTimeKind.Local);
}
Si la hora no es local la convierte a local.

Hola bmfranky, esto es exactamente lo que hago ;)
Pero esto solo crea un DateTime indicando que DateTimeKind es local, luego cuando el serializador o "quien" sea coge ese DateTime para obtener la fecha hora real con el huso, utiliza la configuración de la zona horaria del ordenador donde se ejecuta. y si no es el mismo que el que generó el registro de facturación, pues no indica la misma hora/huso.

Cita:

Empezado por bmfranky (Mensaje 563860)
Hola, habeis probado a pasar el Date, como un parametro al mismo tiempo que enviais el registro y usarlo para generar la huella, asi seguro que es el mismo....

Osea que consultais la fecha hora al ordenador que hace el envio y la usais para generar el registro y la huella, asi seguro que es la misma, con unos segundos de diferencia.
El ordenador que hace el envio a su vez la consulta con la base de datos o internet o lo que sea.

Si hago esto funcionaria pero no cumpliría la ley :) Generar el registro y la huella se tiene que hacer al emitir la factura y no al enviar.

Pero gracias de todas formas.

De momento he prohibido que haya configuraciones de zona horaria distintas en todos los ordenadores que ejecutan el programa con la misma base de datos.
Si no encuentro otra solución lo dejaré así.

Saludos

bmfranky 17-04-2025 09:14:34

Cita:

Empezado por rci (Mensaje 563873)
Hola bmfranky, esto es exactamente lo que hago ;)
Pero esto solo crea un DateTime indicando que DateTimeKind es local, luego cuando el serializador o "quien" sea coge ese DateTime para obtener la fecha hora real con el huso, utiliza la configuración de la zona horaria del ordenador donde se ejecuta. y si no es el mismo que el que generó el registro de facturación, pues no indica la misma hora/huso.



Si hago esto funcionaria pero no cumpliría la ley :) Generar el registro y la huella se tiene que hacer al emitir la factura y no al enviar.

Pero gracias de todas formas.

De momento he prohibido que haya configuraciones de zona horaria distintas en todos los ordenadores que ejecutan el programa con la misma base de datos.
Si no encuentro otra solución lo dejaré así.

Saludos

Si, lo entiendo, pero la fecha hora seria la misma, la del sistema que envia, es lo mismo que consultar la hora a la base de datos, pero en este caso es el servidor horario es el ordenador que envia, no incumples ninguna ley, creo que no me he explicado bien
A lo que me refiero es a que implementeis la funcion que consulta la hora solo en el ordenador que envia y que los demas se la pidan a el.

rci 17-04-2025 09:20:19

Cita:

Empezado por bmfranky (Mensaje 563874)
A lo que me refiero es a que implementeis la funcion que consulta la hora solo en el ordenador que envia y que los demas se la pidan a el.

Ah perdona, no había entendido.

Si, de esta forma también funcionaria, pero es un poco mas complicado. Lo tendré en cuenta.

Gracias

FelixDL 18-04-2025 18:42:15

Yo para obtener el valor de "FechaHoraHusoGenRegistro" en SQL Server uso:

select @ls_valor = left(convert(nvarchar(33), sysdatetimeoffset(), 126), 19) + right(convert(nvarchar(33), sysdatetimeoffset(), 126), 6)

Saludos

rci 22-04-2025 09:07:25

Cita:

Empezado por FelixDL (Mensaje 563887)
Yo para obtener el valor de "FechaHoraHusoGenRegistro" en SQL Server uso:

select @ls_valor = left(convert(nvarchar(33), sysdatetimeoffset(), 126), 19) + right(convert(nvarchar(33), sysdatetimeoffset(), 126), 6)

Saludos


Muchas gracias por la respuesta FelixDL
De esta forma se obtiene directamente una cadena, pero trabajando con objetos tengo el mismo problema

bmfranky 22-04-2025 09:13:14

Cita:

Empezado por rci (Mensaje 563922)
Muchas gracias por la respuesta FelixDL
De esta forma se obtiene directamente una cadena, pero trabajando con objetos tengo el mismo problema

Hola, @rci , prueba a crear desde esa cadena el System.DateTime, y se lo pasas al componente a ver si soluciona tu problema.

rci 22-04-2025 09:57:18

Cita:

Empezado por bmfranky (Mensaje 563924)
Hola, @rci , prueba a crear desde esa cadena el System.DateTime, y se lo pasas al componente a ver si soluciona tu problema.

Muchas gracias bmfranky por la respuesta. pero el tema es el mismo. la transformación de string a DateTime depende de la configuración del huso horario del ordenador donde se ejecuta la conversión.

bmfranky 22-04-2025 14:19:28

Cita:

Empezado por rci (Mensaje 563926)
Muchas gracias bmfranky por la respuesta. pero el tema es el mismo. la transformación de string a DateTime depende de la configuración del huso horario del ordenador donde se ejecuta la conversión.

Pues entonces la unica solucion, la que has tomado, no permitir diferentes usos horarios, en una misma instalacion.

rafa1963 06-05-2025 12:05:35

Error FechaHoraHusoGenRegistro al enviar factura
 
Buenas tardes compañeros al intentar enviar unas facturas de prueba me lanza este error .A202500495 AceptadoConErrores 2004 El valor del campo FechaHoraHusoGenRegistro debe ser la fecha actual del sistema de la AEAT, admitiéndose un margen de error de: 240 segundos.
He comprobado mil veces la hora actual del sistema y está todo correcto.

me podeis echar una manita ????.
Gracias

gcqZW 06-05-2025 12:10:21

En principio esos errores no hay que subsanarlos, si no pones que valor envías poco te podemos ayudar. Por lo pronto fíjate a ver el tema de zona horaria, si no me equivoco ahora estamos en +2.

rafa1963 06-05-2025 12:28:30

Respuesta a gcqZW
 
Gracias gcqZW, comprobaré la zona horaria.

rafa1963 06-05-2025 12:44:57

Resuelto
 
He Activado la opción para Establecer la zona horaria automáticamente y ya está solucionado.
Gracias compañero gcqZW por tu ayuda.
.

Neftali [Germán.Estévez] 06-05-2025 12:53:02

Voy a unirlo con el tema ya existente sobre esto.
Recordad realizar búsquedas antes de crear nuevas preguntas, para no repetir temas.

Gracias.

VJSoftware 07-05-2025 13:34:18

Cita:

Empezado por rci (Mensaje 563873)
Hola bmfranky, esto es exactamente lo que hago ;)
Pero esto solo crea un DateTime indicando que DateTimeKind es local, luego cuando el serializador o "quien" sea coge ese DateTime para obtener la fecha hora real con el huso, utiliza la configuración de la zona horaria del ordenador donde se ejecuta. y si no es el mismo que el que generó el registro de facturación, pues no indica la misma hora/huso.



Si hago esto funcionaria pero no cumpliría la ley :) Generar el registro y la huella se tiene que hacer al emitir la factura y no al enviar.

Pero gracias de todas formas.

De momento he prohibido que haya configuraciones de zona horaria distintas en todos los ordenadores que ejecutan el programa con la misma base de datos.
Si no encuentro otra solución lo dejaré así.

Saludos

Tengo un software de TPV instalado en una tienda que hace, en los días grandes, alrededor de 500 tickets. Paso a comentaros mi problemática.
Parto de estas premisas que me ha parecido leer:
1.- Hay que mandar los registros de facturación cada 60 segundos o cada 1000 registros, lo que antes suceda.
2.- No se pueden hacer nuevos envíos si no han pasado 240 segundos desde el envío anterior. este mensaje lo he recibido a veces como respuesta de la AEAT y es absolutamente incompatible con el primero.

Y ahora mis preguntas
¿Si voy haciendo tickets y generando a la vez sus RF hay que estar pendiente de enviarlos antes de que pasen los 60 segundos?
Si fuera así entonces si hago un ticket ahora con su RF y lo envío y viene otro ticket y lo quiero enviar, no me va a dejar porque no han pasado los 240 segundos desde el envío anterior......
¿Puedo hacer los tickets y después, cuando se vayan a enviar, generar los RF por ejemplo al final del día?
¿Puedo hacer los RF a futuro?, me explico, si ahora son las 12:00:00 y hago ahora los RF de 200 tickets, puedo ponerles como fechahorahuso las 12:15:00 y cuando llegue esa hora realmente, enviarlos?

Gracias por las respuestas de antemano

gcqZW 07-05-2025 13:37:06

No, el problema viene con el QR, si has impreso el ticket has tenido que enviar el RF a la AEAT previamente.

VJSoftware 07-05-2025 13:43:59

Cita:

Empezado por gcqZW (Mensaje 564317)
No, el problema viene con el QR, si has impreso el ticket has tenido que enviar el RF a la AEAT previamente.

Pero no es así. Si te das cuenta, en el QR solamente interviene la fecha, no la hora...
Entonces, yo puedo imprimir un ticket con su QR perfectamente pero, si el cliente trata de verificarlo en ese instante, le va a decir que aún no está en hacienda. Quizás dentro de 10 minutos ya lo mande...
Aquí el QR no influye para nada.

rci 07-05-2025 13:52:29

Cita:

Empezado por VJSoftware (Mensaje 564316)
1.- Hay que mandar los registros de facturación cada 60 segundos o cada 1000 registros, lo que antes suceda.

Este valor de 60 segundos, puede variar en cada envío (de momento no lo hace) pero la normativa dice que de cada respuesta de un envío debemos leer el nuevo tiempo de espera.

Cita:

Empezado por VJSoftware (Mensaje 564316)
2.- No se pueden hacer nuevos envíos si no han pasado 240 segundos desde el envío anterior. este mensaje lo he recibido a veces como respuesta de la AEAT y es absolutamente incompatible con el primero.

NO lo has entendido bien. El error te dice que han pasado MAS de 240 segundos desde que generaste el registro de facturación, por lo tanto que lo estás enviando TARDE.


Cita:

Empezado por VJSoftware (Mensaje 564316)
¿Si voy haciendo tickets y generando a la vez sus RF hay que estar pendiente de enviarlos antes de que pasen los 60 segundos?
Si fuera así entonces si hago un ticket ahora con su RF y lo envío y viene otro ticket y lo quiero enviar, no me va a dejar porque no han pasado los 240 segundos desde el envío anterior......

El SIF tiene que ir haciendo registros de facturación en el momento que emita las facturas y en paralelo se tiene que ir enviando los registros de facturación pendientes de envío, cada cuando toque, siguiendo la normativa del control de flujo, cada X tiempo (normalmente 60 s) o si ya hay 1000 RFs pendientes.


Cita:

Empezado por VJSoftware (Mensaje 564316)
¿Puedo hacer los tickets y después, cuando se vayan a enviar, generar los RF por ejemplo al final del día?

Según la ley NO puedes hacer esto. La ley dice que el registro de facturación se tiene que crear en el momento de emitir la factura.

Cita:

Empezado por VJSoftware (Mensaje 564316)
¿Puedo hacer los RF a futuro?, me explico, si ahora son las 12:00:00 y hago ahora los RF de 200 tickets, puedo ponerles como fechahorahuso las 12:15:00 y cuando llegue esa hora realmente, enviarlos?

Según la ley NO puedes hacer esto. La ley dice que el registro de facturación se tiene que crear en el momento de emitir la factura.

Jarogo08 07-05-2025 13:54:26

Cita:

Empezado por VJSoftware (Mensaje 564316)
Parto de estas premisas que me ha parecido leer:
1.- Hay que mandar los registros de facturación cada 60 segundos o cada 1000 registros, lo que antes suceda.
2.- No se pueden hacer nuevos envíos si no han pasado 240 segundos desde el envío anterior. este mensaje lo he recibido a veces como respuesta de la AEAT y es absolutamente incompatible con el primero.

Y ahora mis preguntas
¿Si voy haciendo tickets y generando a la vez sus RF hay que estar pendiente de enviarlos antes de que pasen los 60 segundos?
Si fuera así entonces si hago un ticket ahora con su RF y lo envío y viene otro ticket y lo quiero enviar, no me va a dejar porque no han pasado los 240 segundos desde el envío anterior......
¿Puedo hacer los tickets y después, cuando se vayan a enviar, generar los RF por ejemplo al final del día?
¿Puedo hacer los RF a futuro?, me explico, si ahora son las 12:00:00 y hago ahora los RF de 200 tickets, puedo ponerles como fechahorahuso las 12:15:00 y cuando llegue esa hora realmente, enviarlos?


-Cuando haces un envío en la respuesta te dice cuando tienes que esperar para hacer el siguiente envío. A mí por ahora siempre me devuelve 60, no 240. La premisa número 2 diría que es falsa

En cuanto a las preguntas...

Si tienes un proceso que salte cada 60 segundos (o los segundos que diga la respuesta del último envío) para revisar si hay algo pendiente de enviar y si lo hay que lo envíe, ya te responde a las 2 primeras preguntas:
Si el proceso salta ahora mismo y no hay nada pendiente vuelve a saltar dentro de 60 segundos. En ese momento va a haber x tickets (los que se hicieron en esos 60 segundos: 0, 1 o 50) y los envía. Dentro de otros 60 segundos volverá a enviar otros X... y así por los siglos de los siglos :D Vamos a suponer que en ese minuto no aparecen 1000 tickets, sino sí que tendrías que mandar antes (nosotros por ahora no contemplamos ese caso, no somos capaces de hacer 1000 documentos en un minuto)
-La tercera pregunta: NO, los RF tienen que crearse y enviarse prácticamente al momento de terminar el ticket, con esos x (60) segundos de margen para el envío (pero no para la creación del RF)
-La cuarta pregunta: NO, lo mismo que la anterior

EDITO: rci ya te lo ha contestado perfectamente!

aleixep 07-05-2025 13:58:56

Hola VJSoftware, la primera premisa es correcta, pero no la segunda.

Como bien mencionas, entre envío y envío deben pasar mínimo 60 segundos (este valor es variable, pues la AEAT especificará en la respuesta el valor exacto), o que haya 1000 registros en cola (en este caso, se ignora el tiempo de espera). Por lo tanto, si se genera un registro y se envía, el próximo grupo de registros no podrá enviarse hasta pasado ese tiempo.

Ahora bien, lo de los 240 segundos es otro tema. Si sale ese error se refiere a que, desde que se ha generado el registro hasta que se ha enviado a la AEAT, han pasado más de 240 segundos. La AEAT quiere que los registros se envíen automáticamente cuando se generan (o con los 60 segundos de espera que hablábamos antes). Por lo tanto, si han pasado más de 240 segundos, la AEAT considera que es un error.

¡Espero que te haya servido para aclarar un poco el tema!

Edito: tanto rci como Jarogo08 han respondido de forma muy completa, ¡parece que varios hemos respondido a la vez!

Neftali [Germán.Estévez] 07-05-2025 14:03:11

Cita:

Empezado por VJSoftware (Mensaje 564316)
Parto de estas premisas que me ha parecido leer:
1.- Hay que mandar los registros de facturación cada 60 segundos o cada 1000 registros, lo que antes suceda.
2.- No se pueden hacer nuevos envíos si no han pasado 240 segundos desde el envío anterior. este mensaje lo he recibido a veces como respuesta de la AEAT y es absolutamente incompatible con el primero.

Yo creo que te estás haciendo un lío con los tiempos.
Por defecto los 60 sg. es el tiempo que debes esperar entre envíos de registros de facturación. Es decir, no puedes estar haciendo envíos cada 3 sg. (*1*)
Los 240 sg. es el tiempo máximo que tener entre que se genera un Registro de Facturación y se envía. (*2*)

Es decir, no quieren que envíes cada 5 sg. (*1*), pero que tampoco envíes cada 4 horas (*2*).
El tiempo de 60 sg. entre un envío y otro, se puede ampliar (lo devuelve la AEAT en cada envío). Es de suponer que cuando ese tiempo se amplíe (el de 60sg.) también lo harán con el otro (el de 240sg.).


Cita:

Empezado por VJSoftware (Mensaje 564316)
¿Si voy haciendo tickets y generando a la vez sus RF hay que estar pendiente de enviarlos antes de que pasen los 60 segundos?

Lo lógico es hacer envíos cada 60 sg. aproximadamente para evitar problemas. Mientras que la AEAT no modifique ese tiempo.
Nosotros tenemos un servicio que cada 60 sg. realiza en envío de lo que haya pendiente (puede ser 0, 1 o 200 tickets/facturas). NOTA: En nuestro caso no comprobamos que haya 1000 porque en nuestro sistema eso no se va a dar.

Cita:

Empezado por VJSoftware (Mensaje 564316)
Si fuera así entonces si hago un ticket ahora con su RF y lo envío y viene otro ticket y lo quiero enviar, no me va a dejar porque no han pasado los 240 segundos desde el envío anterior......
¿Puedo hacer los tickets y después, cuando se vayan a enviar, generar los RF por ejemplo al final del día?

Yo creo que no.
Lo correcto (creo yo) es generar la factura/ticket y en ese momento generar el Registro de Facturación. Y dejarlo pendiente de enviar hasta el momento que envíes ese y el resto que tenga pendientes (cada 60 sg. como hemos dicho).

Cita:

Empezado por VJSoftware (Mensaje 564316)
¿Puedo hacer los RF a futuro?, me explico, si ahora son las 12:00:00 y hago ahora los RF de 200 tickets, puedo ponerles como fechahorahuso las 12:15:00 y cuando llegue esa hora realmente, enviarlos?

Creo que con la anterior ya está respondido. Yo no le veo sentido a eso.

Cita:

Empezado por gcqZW (Mensaje 564317)
No, el problema viene con el QR, si has impreso el ticket has tenido que enviar el RF a la AEAT previamente.

No.
Los Registro de Facturación y el QR pueden, y yo creo que deben, generarse independientemente del envío.
Lo normal es porque el envío se hará más tarde (entre 1 y 60 sg. más tarde).
Pero también en casos "anormales", por ejemplo porque los servidores de la AEAT han "caído" (durante 2 horas), y debes poder seguir trabajando, generando tickets, dándoselos al cliente,... aunque no puedas enviar o los envíos no funcionen.

Cita:

Empezado por VJSoftware (Mensaje 564322)
Pero no es así. Si te das cuenta, en el QR solamente interviene la fecha, no la hora...
Entonces, yo puedo imprimir un ticket con su QR perfectamente pero, si el cliente trata de verificarlo en ese instante, le va a decir que aún no está en hacienda. Quizás dentro de 10 minutos ya lo mande...
Aquí el QR no influye para nada.

Correcto.
Es posible que surante un tiempo el ticket/factura con QR esté generado, pero todavía no sea "consultable".
Eso se assume.

gcqZW 07-05-2025 14:09:13

Cita:

Aquí el QR no influye para nada.
A lo que me refiero a que no es que te impida programáticamente hacerlo sino que no deberías entregar un QR que no se pueda comprobar (por lo menos en el rato cercano a la entrega del mismo). No vas a ir repartiendo facturas a diestro y siniestro y mandar los RF cuando te de por ahí.

VJSoftware 07-05-2025 14:10:13

NO lo has entendido bien. El error te dice que han pasado MAS de 240 segundos desde que generaste el registro de facturación, por lo tanto que lo estás enviando TARDE.

Vale, entiendo. Pero te agradecería que abundáramos un poco más en este tema.

Voy creando los RF de los tickets.
Tengo un proceso por debajo que comprueba si se va a cumplir el tiempo de espera fijado por la AEAT (60 segundos)
Antes de que se cumpla, realizo el envío de todos los RF pendientes y tomo nota del nuevo margen de tiempo para el siguiente envío.
Así sucesivamente.
¿Eso es lo que me dices?


El error que se recibe es: El valor del campo FechaHoraHusoGenRegistro debe ser la fecha actual del sistema de la AEAT, admitiéndose un margen de error de: 240 segundos.

Entonces podemos enviar cada 200 segundos, por ejemplo, y admitiría todo los RF que haya hasta entonces. ¿Es así?

Muchas gracias de antemano

VJSoftware 07-05-2025 14:13:53

Cita:

Empezado por Neftali [Germán.Estévez] (Mensaje 564329)
Yo creo que te estás haciendo un lío con los tiempos.
Por defecto los 60 sg. es el tiempo que debes esperar entre envíos de registros de facturación. Es decir, no puedes estar haciendo envíos cada 3 sg. (*1*)
Los 240 sg. es el tiempo máximo que tener entre que se genera un Registro de Facturación y se envía. (*2*)

Es decir, no quieren que envíes cada 5 sg. (*1*), pero que tampoco envíes cada 4 horas (*2*).
El tiempo de 60 sg. entre un envío y otro, se puede ampliar (lo devuelve la AEAT en cada envío). Es de suponer que cuando ese tiempo se amplíe (el de 60sg.) también lo harán con el otro (el de 240sg.).




Lo lógico es hacer envíos cada 60 sg. aproximadamente para evitar problemas. Mientras que la AEAT no modifique ese tiempo.
Nosotros tenemos un servicio que cada 60 sg. realiza en envío de lo que haya pendiente (puede ser 0, 1 o 200 tickets/facturas). NOTA: En nuestro caso no comprobamos que haya 1000 porque en nuestro sistema eso no se va a dar.


Yo creo que no.
Lo correcto (creo yo) es generar la factura/ticket y en ese momento generar el Registro de Facturación. Y dejarlo pendiente de enviar hasta el momento que envíes ese y el resto que tenga pendientes (cada 60 sg. como hemos dicho).



Creo que con la anterior ya está respondido. Yo no le veo sentido a eso.



No.
Los Registro de Facturación y el QR pueden, y yo creo que deben, generarse independientemente del envío.
Lo normal es porque el envío se hará más tarde (entre 1 y 60 sg. más tarde).
Pero también en casos "anormales", por ejemplo porque los servidores de la AEAT han "caído" (durante 2 horas), y debes poder seguir trabajando, generando tickets, dándoselos al cliente,... aunque no puedas enviar o los envíos no funcionen.



Correcto.
Es posible que surante un tiempo el ticket/factura con QR esté generado, pero todavía no sea "consultable".
Eso se assume.

OK. Muchas gracias por tu tiempo. Un saludo.

Neftali [Germán.Estévez] 07-05-2025 15:07:55

Cita:

Empezado por VJSoftware (Mensaje 564331)
Voy creando los RF de los tickets.
Tengo un proceso por debajo que comprueba si se va a cumplir el tiempo de espera fijado por la AEAT (60 segundos)
Antes de que se cumpla, realizo el envío de todos los RF pendientes y tomo nota del nuevo margen de tiempo para el siguiente envío.
Así sucesivamente.
¿Eso es lo que me dices?

Todo correcto, excepto el "antes de que se cumpla".
En el caso por defecto NO deberás hacer el envío antes de los 60 sg. y no después de los 240.

Cita:

Empezado por VJSoftware (Mensaje 564331)
Entonces podemos enviar cada 200 segundos, por ejemplo, y admitiría todo los RF que haya hasta entonces. ¿Es así?

Eso.
Puedes enviar cada 70, 120, 180 o 200, (si estamos hablando de los 60 sg. que es el valor por defecto).
En todos esos casos es correcto porque se cumple: >60 y < 240.

Si la AEAT cambia ese valor por defecto (60 sg.) habrá que reevaluar.


La franja horaria es GMT +2. Ahora son las 01:08:16.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2026, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi