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)
-   -   ¿Qué (posibles) errores comprobáis antes de guardar la factura? (https://www.clubdelphi.com/foros/showthread.php?t=97438)

espinete 30-04-2025 11:09:36

¿Qué (posibles) errores comprobáis antes de guardar la factura?
 
Buenas!

Pues eso. Imagino que hacéis comprobaciones antes de permitir guardar/emitir la factura, para evitar algunos de los problemas más comunes cuando ésta se envíe.
Nosotros comprobamos/validamos el NIF del Emisor (si no es una fac. simplificada) y el del Destinatario, el certificado digital (que no esté caducado, etc.), si se trata de un cliente extranjero, que esté definido el País, etc.

Hay muchísimas validaciones que se podrían hacer, pero no sé si currármelas todas con un un "super validador" o centrarme solo en los problemas más comunes y ya si luego da error, que el usuario subsane o rectifique según proceda.

¿Alguna validación previa más que consideráis importante?

rci 30-04-2025 11:29:39

Cita:

Empezado por espinete (Mensaje 564152)
Buenas!

Pues eso. Imagino que hacéis comprobaciones antes de permitir guardar/emitir la factura, para evitar algunos de los problemas más comunes cuando ésta se envíe.
Nosotros comprobamos/validamos el NIF del Emisor (si no es una fac. simplificada) y el del Destinatario, el certificado digital (que no esté caducado, etc.), si se trata de un cliente extranjero, que esté definido el País, etc.

Hay muchísimas validaciones que se podrían hacer, pero no sé si currármelas todas con un un "super validador" o centrarme solo en los problemas más comunes y ya si luego da error, que el usuario subsane o rectifique según proceda.

¿Alguna validación previa más que consideráis importante?

Nosotros una vez generado en memoria el objeto del registro de facturación, antes de salvarlo se lanza una función que hace TODAS las validaciones del fichero de validaciones de la documentación:
https://www.agenciatributaria.es/sta...Veri-Factu.pdf

Si alguna validación no se supera, se informa al usuario y no se permite salvar la venta.

espinete 30-04-2025 12:01:27

Cita:

Empezado por rci (Mensaje 564156)
Nosotros una vez generado en memoria el objeto del registro de facturación, antes de salvarlo se lanza una función que hace TODAS las validaciones del fichero de validaciones de la documentación:
https://www.agenciatributaria.es/sta...Veri-Factu.pdf

Si alguna validación no se supera, se informa al usuario y no se permite salvar la venta.

Pues sí que te has pegado un buen curro. Me parece bien, porque es lo ideal y a la larga te ahorra dolores de cabeza.
Yo hasta ahora me he centrado en todo lo demás. Como aún queda tiempo, quizás vaya añadiendo más validaciones previas poco a poco.

bmfranky 30-04-2025 14:34:19

Yo personalmente, como no tengo pensado emitir facturas sin que haya conexion, uso el sistema de validacion que han implementado para los no verifactu, que es el mismo que se usa para el verifactu, si pasa la verificacion, ya guardo , envio e imprimo la factura con total seguridad de que es correcta, si no lo es , como aun estoy en fase de *diseño de la misma, pues puedo correjir lo que haga falta, e incluso salir sin guardar nada descartando cualquier cambio, en la base de datos, puesto que la factura no se ha finalizado....


Aunque si , esa super funcion de comprobacion , de @rci para el modo offline, serida suprema.... *Se aceptan donaciones de codigo.... :cool::cool:

newtron 30-04-2025 17:31:07

Es buena idea validar de forma "TOTAL" la factura antes de guardarla pero se me ocurre que eso puede traer algún problema que otro:


1- Entiendo que la factura debe de tener su número para poder validarla, si por lo que sea hay algún error y no dejáis guardarla/enviarla entiendo que el proceso se atasca. En ambientes de red, si otro está facturando por otro sitio entiendo que debería de dejarle enviar la factura siendo correcta y esta llevará un número posterior. Si al final la factura atascada no se puede llevar a término por el motivo que sea tendremos un problema y no sé si también aunque al final se envíe si se hace con una fecha+hora posterior a una factura posterior.
2- Igualmente si hay "bulla" y una factura se "atasca" se puede atascar igualmente la cosa con otros clientes que haya esperando.
3- Si por el motivo que sea no hay internet se debe de poder emitir la factura aunque se envíe posteriormente con incidencia (es mi opinión).


Saludos.

rci 30-04-2025 18:10:13

Cita:

Empezado por newtron (Mensaje 564165)
Es buena idea validar de forma "TOTAL" la factura antes de guardarla pero se me ocurre que eso puede traer algún problema que otro:
1- Entiendo que la factura debe de tener su número para poder validarla, si por lo que sea hay algún error y no dejáis guardarla/enviarla entiendo que el proceso se atasca. En ambientes de red, si otro está facturando por otro sitio entiendo que debería de dejarle enviar la factura siendo correcta y esta llevará un número posterior. Si al final la factura atascada no se puede llevar a término por el motivo que sea tendremos un problema y no sé si también aunque al final se envíe si se hace con una fecha+hora posterior a una factura posterior.

En C# .Net (no se si será igual en Delphi) el proceso de salvar una factura se hace dentro de una misma transacción de base de datos.
Dentro de ese proceso se busca el numero que le toca en una tabla de contadores y se actualiza esa tabla para que la siguiente factura no coja el mismo número.
Dentro de esa misma transacción también se crea el registro de facturación, con el número asignado y también dentro de esa transacción se hacen las validaciones.
Si alguna validación falla, se lanza un error y el proceso de salvar se cancela y se deshace toda la transacción (RollBack).
Por lo tanto no se guarda la venta, no se guarda registro de facturación pero tampoco se guarda la información del contador, el numero de factura que toca.
De esta forma, si "al segundo siguiente" otro ordenador quiere salvar una factura, hará el mismo proceso y cogerá el mismo número que el SIF quería utilizar para la factura que ha fallado en la validación, el que toca en ese momento.
Si ese segundo ordenador no tiene errores podrá salvar la factura.
El primer ordenador, que no ha podido salvar por un error en la validación, cuando corrija el problema y vuelva a salvar la factura, cogerá otro numero (el que toque) y si no hay errores pues salvará la factura y el registro de facturación con los nuevos datos.


Cita:

Empezado por newtron (Mensaje 564165)
2- Igualmente si hay "bulla" y una factura se "atasca" se puede atascar igualmente la cosa con otros clientes que haya esperando.

El único "bloqueo" ocurre en el lapso de tiempo que el SIF intenta salvar la factura (incluido todo el proceso de crear el registro de facturación y validarlo) pero habitualmente es muy rápido.

Cita:

Empezado por newtron (Mensaje 564165)
3- Si por el motivo que sea no hay internet se debe de poder emitir la factura aunque se envíe posteriormente con incidencia (es mi opinión).

No hace falta internet para nada, la validación que comento solo comprueba los valores del registro de facturación que se está creando en memoria.


Seguro que se puede mejorar y también seguramente encontraremos algunos problemas pero de momento está funcionando.

Cita:

Empezado por bmfranky (Mensaje 564162)
Yo personalmente, como no tengo pensado emitir facturas sin que haya conexion, uso el sistema de validacion que han implementado para los no verifactu, que es el mismo que se usa para el verifactu, si pasa la verificacion, ya guardo , envio e imprimo la factura con total seguridad de que es correcta, si no lo es , como aun estoy en fase de *diseño de la misma, pues puedo correjir lo que haga falta, e incluso salir sin guardar nada descartando cualquier cambio, en la base de datos, puesto que la factura no se ha finalizado....

Esta también es una buena idea, pero si que necesita internet. Pero la idea es la misma. Si falla la validación no se guarda ni se "ocupa" el número.
Esta idea tiene de bueno que las validaciones realmente las hace la AEAT y seguramente son las mismas que se harán al enviar. A parte que cuando AEAT hace cambios en las validaciones, de esta forma no tienes que cambiar nada y con la función que hemos hecho (que también puede tener errores en nuestro código), en cada cambio de la AEAT, tenemos que mantener la función que valida. Esperemos que no cambien mucho.


Saludos

Jarogo08 30-04-2025 18:20:29

Cita:

Empezado por rci (Mensaje 564166)
No hace falta internet para nada, la validación que comento solo comprueba los valores del registro de facturación que se está creando en memoria.

¿Y como haces por ejemplo la comprobación del CIF sin internet? ¿no tiras del web service que la AEAT tiene para eso? ¿o tienes tu propia función de comprobación de CIFs?

en mi caso actualmente no comprobamos nada, tu generas la facturas y el RF, y si luego al enviarse da error pues a corregirla. Igual le tengo que dar una vuelta a esto :confused:

rci 30-04-2025 18:24:50

Cita:

Empezado por Jarogo08 (Mensaje 564168)
¿Y como haces por ejemplo la comprobación del CIF sin internet? ¿no tiras del web service que la AEAT tiene para eso? ¿o tienes tu propia función de comprobación de CIFs?

Si, las dos cosas. El CIF se valida con el algoritmo (que no requiere internet) i también con el web Service de la AEAT, pero si es posible se hace antes de salvar la factura, por ejemplo cuando se indica el cliente o cuando se modifica el CIF o la razón social, así de esta forma, si en el momento de salvar la factura el CIF ya está "marcado internamente" como validado, ya no se tiene que validar de nuevo.

espinete 30-04-2025 18:38:31

Cita:

Empezado por newtron (Mensaje 564165)
1- Entiendo que la factura debe de tener su número para poder validarla, si por lo que sea hay algún error y no dejáis guardarla/enviarla entiendo que el proceso se atasca. En ambientes de red, si otro está facturando por otro sitio entiendo que debería de dejarle enviar la factura siendo correcta y esta llevará un número posterior. Si al final la factura atascada no se puede llevar a término por el motivo que sea tendremos un problema y no sé si también aunque al final se envíe si se hace con una fecha+hora posterior a una factura posterior.
2- Igualmente si hay "bulla" y una factura se "atasca" se puede atascar igualmente la cosa con otros clientes que haya esperando.
3- Si por el motivo que sea no hay internet se debe de poder emitir la factura aunque se envíe posteriormente con incidencia (es mi opinión).

Al menos en nuestro caso, el número de factura no se asigna hasta el momento en que se guarda la factura, si se guarda, claro. Para eso usamos un "semáforo", con bloqueos de la tabla, etc. para evitar duplicados, etc. Que un PC no pueda emitir una factura no afectará a los demás, ni habrá huecos en la enumeración ni nada por el estilo.

Solo afectará a la cola de clientes que estén esperando, pero vamos, si hay cola es probablemente un comercio, donde no hay NIF del cliente ni otras cosas que puedan fallar, así que no será el caso.
Yo lo que haré es comprobar solo algunas de las validaciones, las que más sujetas estén a fallo por parte del usuario. Hay otras que tal como está diseñada la aplicación es imposible que se den nunca.

Por cierto, le he dado a ChatGPT el documento de validaciones y le he pedido que me cree un algoritmo en PHP que haga todas las validaciones del documento. Aún no me he puesto a revisarlo, pero creo que lo ha hecho bastante bien :D

No todas estas validaciones pueden hacerse ANTES de guardar la factura, y no todas requieren validación, pero algo se podrá aprovechar:

Código PHP:

<?php
function verifactu_precheck(array $datos): array {
    
$errores = [];

    
// Variables locales (usa isset para evitar errores de undefined)
    
$tipo_factura $datos['TipoFactura'] ?? '';
    
$tipo_rectificativa $datos['TipoRectificativa'] ?? '';
    
$calificacion $datos['CalificacionOperacion'] ?? '';
    
$clave_regimen $datos['ClaveRegimen'] ?? '';
    
$operacion_exenta $datos['OperacionExenta'] ?? '';
    
$tipo_impositivo $datos['TipoImpositivo'] ?? null;
    
$tipo_recargo_equivalencia $datos['TipoRecargoEquivalencia'] ?? null;
    
$cuota_repercutida $datos['CuotaRepercutida'] ?? null;
    
$cuota_recargo_equivalencia $datos['CuotaRecargoEquivalencia'] ?? null;
    
$base_imponible $datos['BaseImponibleOimporteNoSujeto'] ?? null;
    
$base_imponible_coste $datos['BaseImponibleACoste'] ?? null;
    
$impuesto $datos['Impuesto'] ?? '';
    
$fecha_operacion $datos['FechaOperacion'] ?? date('Y-m-d');
    
$factura_sin_identif_destinatario $datos['FacturaSinIdentifDestinatarioArticulo61d'] ?? '';
    
$num_registro_acuerdo $datos['NumRegistroAcuerdoFacturacion'] ?? '';

    
// CalificacionOperacion S2
    
if ($calificacion === 'S2') {
        if (!
in_array($tipo_factura, ['F1','F3','R1','R2','R3','R4'])) {
            
$errores[] = "La Calificación 'S2' solo es válida con TipoFactura F1, F3, R1, R2, R3 o R4.";
        }
        if (
$tipo_impositivo !== 0) {
            
$errores[] = "Si la Calificación es 'S2', el TipoImpositivo debe ser 0.";
        }
        if (
$cuota_repercutida != 0) {
            
$errores[] = "Si la Calificación es 'S2', la CuotaRepercutida debe ser 0.";
        }
    }

    
// CalificacionOperacion N1/N2
    
if (in_array($calificacion, ['N1''N2']) && ($impuesto === '01' || $impuesto === '')) {
        if (!empty(
$tipo_impositivo) && $clave_regimen !== '17') {
            
$errores[] = "TipoImpositivo no debe informarse si Calificación es N1/N2 y ClaveRegimen no es 17.";
        }
        if (!empty(
$cuota_repercutida) && $clave_regimen !== '17') {
            
$errores[] = "CuotaRepercutida no debe informarse si Calificación es N1/N2 y ClaveRegimen no es 17.";
        }
        if (!empty(
$tipo_recargo_equivalencia)) {
            
$errores[] = "TipoRecargoEquivalencia no debe informarse si Calificación es N1/N2.";
        }
        if (!empty(
$cuota_recargo_equivalencia)) {
            
$errores[] = "CuotaRecargoEquivalencia no debe informarse si Calificación es N1/N2.";
        }
    }

    
// OperacionExenta con campos incompatibles
    
if (!empty($operacion_exenta)) {
        if (!empty(
$tipo_impositivo) || !empty($cuota_repercutida) || !empty($tipo_recargo_equivalencia) || !empty($cuota_recargo_equivalencia)) {
            
$errores[] = "Si se informa OperacionExenta, no deben informarse TipoImpositivo, CuotaRepercutida ni Recargo de Equivalencia.";
        }
    }

    
// TipoImpositivo permitido según fecha y CalificacionOperacion
    
if (($impuesto === '01' || $impuesto === '03' || $impuesto === '') && $calificacion === 'S1') {
        
$permitidos = [02457.51021];
        if (
$fecha_operacion >= '2022-07-01' && $fecha_operacion <= '2024-09-30'$permitidos[] = 5;
        if (
$fecha_operacion >= '2024-10-01' && $fecha_operacion <= '2024-12-31'array_push($permitidos27.5);
        if (!
in_array($tipo_impositivo$permitidos)) {
            
$errores[] = "TipoImpositivo no válido para CalificacionOperacion S1 en la fecha dada.";
        }
    }

    
// Factura simplificada F2
    
if ($tipo_factura === 'F2') {
        
$importe_total $base_imponible $cuota_repercutida;
        if (
$importe_total 3010 && $factura_sin_identif_destinatario !== 'S' && empty($num_registro_acuerdo)) {
            
$errores[] = "Factura F2 no puede superar los 3.000€ (+10€ de margen) salvo acuerdo o identificación del destinatario.";
        }
    }

    
// ASCII en NumSerieFactura
    
if (!empty($datos['NumSerieFactura']) && !preg_match('/^[\x20-\x7E]+$/'$datos['NumSerieFactura'])) {
        
$errores[] = "El número de serie solo puede contener caracteres ASCII imprimibles.";
    }

    
// Huella en formato SHA-256
    
if (!empty($datos['Huella']) && !preg_match('/^[A-F0-9]{64}$/'$datos['Huella'])) {
        
$errores[] = "La huella debe tener 64 caracteres hexadecimales en mayúsculas (formato SHA-256).";
    }

    return 
$errores;
}


bmfranky 30-04-2025 18:45:06

Pues la funcion que postee, funciona perfectamente, hasta me ha salido un error oculto que tenia en la llamada a la funcion que me bajaba la hora del roa, al caer eñl servicio me ha diagnosticado que insertaba decimales, todo antes de enviar nada realmente a la AEAT, al no ser un envio aunque falles, no reza en ningun sitio...


La franja horaria es GMT +2. Ahora son las 09:19:09.

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