Foros Club Delphi

Foros Club Delphi (https://www.clubdelphi.com/foros/index.php)
-   Envío de registros y sus respuestas (https://www.clubdelphi.com/foros/forumdisplay.php?f=66)
-   -   Demo con código Verifactu.dll para (delphi 7) (https://www.clubdelphi.com/foros/showthread.php?t=97004)

seccion_31 02-02-2025 09:06:58

Hay algunas cosas que me gustaria comentar

1) Alguien ha conseguido hacer funcionar el httprio desde una DLL ? si fuera asi, y tuviera el codigo, lo cambiaria a funcionamiento por DLL que me parece mas elegante.

2) ¿Alguien ha probado el componente, indicando en vez del nombre del certificado el nombre de un archivo.pfx y en passwordCertificado su contraseña?

Saludos !

ramherfer 02-02-2025 11:10:34

Cita:

Empezado por seccion_31 (Mensaje 561642)

Asegurate que usas la compilacion que deje en el rar. MSG_BERLIN\Win32\Debug\msgverifactu.exe del 2 de enero (no creo que haya otra ahi dentro)

Saludos

Si correcto estoy usando esa del 2 de enero de 2025 de las 12:46

Cita:

Empezado por seccion_31 (Mensaje 561642)

Despues del envio, puedes abrir el servidor verifactu de la barra de tareas, ir a la pestaña de la sesion y ver a partir de que factura se activa la incidencia. (de ahi en adelante todo va con incidencia)

Saludos

ok en la primera que he confeccionado hoy y enviado ya me sale incidencia activa.

https://drive.google.com/file/d/17qT...ew?usp=sharing

Voy a revisar mi código a ver si veo algo raro comparandolo con la demo y si no veo nada haré lo propio con el del servidor.

ramherfer 02-02-2025 12:29:50

Cita:

Empezado por ramherfer (Mensaje 561644)
Si correcto estoy usando esa del 2 de enero de 2025 de las 12:46



ok en la primera que he confeccionado hoy y enviado ya me sale incidencia activa.

https://drive.google.com/file/d/17qT...ew?usp=sharing

Voy a revisar mi código a ver si veo algo raro comparandolo con la demo y si no veo nada haré lo propio con el del servidor.

encontrado el problema. Está en la unidad uVerifactuFuncs.pas en la comparación de fechas

Cita:

if factura.actual.fechaFactura<>datetostr(date) then
sesiones[sesion].inicio.incidencia:=true;
Lo he sacado a disco y está comparando esto
Cita:

FechaFactura: 02-02-2025
FechaSistema: 02/02/2025
Siempre son distintas.

la reemplazo por:

Cita:

if factura.actual.fechaFactura<>StringReplace(DateToStr(Date), '/', '-', [rfReplaceAll]) then
sesiones[sesion].inicio.incidencia:=true;

seccion_31 03-02-2025 08:10:06

ramherfer

Creo que estas suministrando la fecha en el record factura.actual.fechaFactura con el formato 01-01-2025 cuando deberías simplemente cargar la fecha tal cual 01/01/2025 cuando se envía la función altafactura_F1_F2_R4_R5_verifactu realiza la conversión.

Ya me lo confirmaras.

Saludos !

DarkDudae 03-02-2025 12:10:03

Cita:

Empezado por seccion_31 (Mensaje 561643)
1) Alguien ha conseguido hacer funcionar el httprio desde una DLL ? si fuera asi, y tuviera el codigo, lo cambiaria a funcionamiento por DLL que me parece mas elegante.

¿Qué problema te da exactamente?

seccion_31 03-02-2025 12:33:46

Cita:

Empezado por DarkDudae (Mensaje 561666)
¿Qué problema te da exactamente?

en la DLL error de proteccion general. justo al llamar la funcion de enviar. El mismo codigo en un ejecutable sin problemas.

googleando en algunos sitios lei que no se podia, pero siempre hay que asegurarse.

ramherfer 03-02-2025 16:10:28

Cita:

Empezado por seccion_31 (Mensaje 561654)
ramherfer

Creo que estas suministrando la fecha en el record factura.actual.fechaFactura con el formato 01-01-2025 cuando deberías simplemente cargar la fecha tal cual 01/01/2025 cuando se envía la función altafactura_F1_F2_R4_R5_verifactu realiza la conversión.

Ya me lo confirmaras.

Saludos !

Efectivamente. Al verlo en las hojas excel con formato dd-mm-aaaa pues pasaba la fecha con el mismo formato.
Ok, corrijo la modificación y realizada.

nincillo 03-02-2025 17:00:37

Cita:

Empezado por seccion_31 (Mensaje 561440)
buenos dias !

Ya tengo disponible una version mas que funcional del componente y servidor de mensajes para D7.

Incluyo la version compilada y codigo fuente del servidor en B10.

Lamentablemente no he podido estar por aqui antes, por motivos personales, pero ahora procurare estar mas atento. especialmente esta semana por si alguien quiere implementarlo.

Lo he tenido que subir a mi google drive porque github no me deja.

https://drive.google.com/file/d/1fKx...usp=drive_link


Aquí no hay milagros, se usa D7 para componer el envío, pero finalmente se transmite atraves de una aplicacion en B10, lo que si es cierto es que mucho mas manejable desde D7.

Se arranca el servidor de mensajes y después de esto, podéis ejecutar la demo (que sube una hoja excel), o empezar desarrollar vuestra aplicacion.

La parte mas imporante es un record que guarda la factura(s), la factura a enviar y la anterior (si existe). El servidor de mensajes se intenta hacer cargo de componer el resto.

Actualmente soporta, facturas, y tickets, y su rectificacion. Ademas se ofrece el control del almacen de certificados, validacion del nif, y el cotejo con la AEAT de los registros enviados.

La cuestión es que hay que probarlo y pulirlo. En teoria es posible utilizarlo con versiones mas alla de D7, directamente sin servidor.

Queda ofrecido aqui como una demostracion, bajo la TOTAL responsabilidad de quien lo utilice.



Saludos cordiales y mucha suerte.

Muchas gracias por este gran aporte.

Voy a intentar compilar tanto la versión D7 como la "moderna" a ver si puedo compilar sin problemas y a partir de ahí empezar a adaptarlo a mi programa.

¿No has podido hacer la parte del envío utilizando D7 y por eso has optado a hacerlo con versiones más modernas?. Yo en su momento, conseguí hacer pruebas de envío, pero el problema lo tenía con el TLS de windows 7. Si el mismo ejecutable lo lanzaba desde un Windows 10 si que parecía funcionar...

Un saludo.

seccion_31 04-02-2025 06:53:48

Cita:

Empezado por nincillo (Mensaje 561677)
Muchas gracias por este gran aporte.

Voy a intentar compilar tanto la versión D7 como la "moderna" a ver si puedo compilar sin problemas y a partir de ahí empezar a adaptarlo a mi programa.

¿No has podido hacer la parte del envío utilizando D7 y por eso has optado a hacerlo con versiones más modernas?. Yo en su momento, conseguí hacer pruebas de envío, pero el problema lo tenía con el TLS de windows 7. Si el mismo ejecutable lo lanzaba desde un Windows 10 si que parecía funcionar...

Un saludo.

No pude hacerlo con D7, ya importando el WSDL creo que tuve problemas, copie la unidad ya importada y habia un monton de tipos que D7 no reconocia, y hasta ahi.

Lo dicho, si alguien sabe como hacer funcionar la llamada SOAP desde una DLL y que no de error general que me avise.

Y me gustaria que alguien probara a usar un archivo PFX en lugar de usar el certificado desde el almacen.

Saludos y gracias !

DarkDudae 04-02-2025 15:29:32

He encontrado un pequeño error en la aplicación servidora.

Si intentas cotejar una factura simple (que por ende no tiene ni cliente ni NIF) arroja una excepción en las líneas:

Código Delphi [-]
cliente             :=res.RegistroRespuestaConsultaFactuSistemaFacturacion[j].DatosRegistroFacturacion.Destinatarios[0].NombreRazon;
clienteNIF          :=res.RegistroRespuestaConsultaFactuSistemaFacturacion[j].DatosRegistroFacturacion.Destinatarios[0].NIF;

Se puede solucionar con un try - except, pero creo que así es mucho mejor:

Código Delphi [-]
if Assigned(res.RegistroRespuestaConsultaFactuSistemaFacturacion[j].DatosRegistroFacturacion.Destinatarios) then
begin
   cliente             :=res.RegistroRespuestaConsultaFactuSistemaFacturacion[j].DatosRegistroFacturacion.Destinatarios[0].NombreRazon;
   clienteNIF          :=res.RegistroRespuestaConsultaFactuSistemaFacturacion[j].DatosRegistroFacturacion.Destinatarios[0].NIF;
end;

Saludos

seccion_31 05-02-2025 06:59:02

gracias DarkDudae

voy a incoporar la corrección y en un tiempo, quizas dos semanas publicare una nueva version.

¿tenemos alguna sugerencia para seguir mejorando el componente?

Voy a retirar el campo "situacion", porque creo que no se usa, y asi libero espacio de la pila.
Corregire las fechas cuando entreguen la fecha de emision con - en lugar de /

Hay un indicador que se llama incidencia, que se puede activar manual, o automaticamente, cuando la fecha de alguna factura es diferente a la del dia.
Habra otro indicador que se llamara primerRegistro si se detecta primer registro en el envio
-->Ambos indicadores, deberian poder ser consultados antes del envio.

(Es una lastima no poder encapsularlo en una DLL, mejoraría mucho)

Habria que probar el certificado pfx

Y hay que añadir mas casos a la generación de la facturación, en especial la de exentos de iva. ¿hay alguien por aqui que domine el tema?

Saludos !

Quim Herrera 05-02-2025 07:44:09

Cita:

Empezado por seccion_31 (Mensaje 561643)
Hay algunas cosas que me gustaria comentar

1) Alguien ha conseguido hacer funcionar el httprio desde una DLL ? si fuera asi, y tuviera el codigo, lo cambiaria a funcionamiento por DLL que me parece mas elegante.

2) ¿Alguien ha probado el componente, indicando en vez del nombre del certificado el nombre de un archivo.pfx y en passwordCertificado su contraseña?

Saludos !

Hola seccion_31 ,
El código del certificado para archivo pfx funciona perfectamente tanto para .pfx como para .p12.
Lo he probado en un servicio de windows que estoy haciendo en delphi 10.2.
Muchas gracias por el aporte!
Saludos,

seccion_31 05-02-2025 08:14:23

hola Quim Herrera !

¿estas seguro que funciona?

ahora mirando la funcion:
Código Delphi [-]
Funcion: procedure TEventosWebNode.WebNodeBeforePost(const HTTPReqResp: THTTPReqResp;
Unidad: uVerifactuFuncs

Yo creo que esto fallara:

Código Delphi [-]
 PFX := TFile.ReadAllBytes('ArchivoDelCertificado.PFX');

Deberia ser:

Código Delphi [-]
  PFX := TFile.ReadAllBytes( cert );


He añadido la extension .P12 para reconocer el archivo

¿puedes confirmarlo por fa?

Slds !

Quim Herrera 05-02-2025 08:31:17

Cita:

Empezado por seccion_31 (Mensaje 561728)
hola Quim Herrera !

¿estas seguro que funciona?

ahora mirando la funcion:

Funcion: procedure TEventosWebNode.WebNodeBeforePost(const HTTPReqResp: THTTPReqResp;
Unidad: uVerifactuFuncs


Yo creo que esto fallara:

PFX := TFile.ReadAllBytes('ArchivoDelCertificado.PFX');

Deberia ser:

PFX := TFile.ReadAllBytes( cert );


He añadido la extension .P12 para reconocer el archivo

¿puedes confirmarlo por fa?

Slds !


Exacto, hay que cambiar
Código Delphi [-]
PFX := TFile.ReadAllBytes('ArchivoDelCertificado.PFX' );
por
Código Delphi [-]
PFX := TFile.ReadAllBytes( cert );
y ya funciona.

Saludos,

seccion_31 05-02-2025 08:34:24

Cuida que: hay que hacer algun cambio mas en la funcion consultar (para que reconoca el PFX), y en los "ifs" para que soporten las dos extensiones.

Ya lo he modificado, perfecto.

gracias !

ramherfer 05-02-2025 13:07:25

Estoy probando el certificado por fichero y contraseña asignandole el path del archivo del archivo de certificdado a la variable VerifactuD7.Certificado y la contraseña en VerifactuD7.passwordCertificado.
No se si es lo correcto, pero me da un error al cotejar.
He realizado la corrección PFX := TFile.ReadAllBytes('ArchivoDelCertificado.PFX' ); por PFX := TFile.ReadAllBytes( cert ); en el servidor antes de hacer la prueba.
Un saludo!

seccion_31 05-02-2025 13:58:38

ramherfer

sustituye esta funcion: uVerifactuFuncs y recompila el servidor B10

Código:

function consultar(sesion:integer; var resultado:TConsultaResultado):boolean;
var
  consulta          : ConsultaFactuSistemaFacturacion;                  // Objeto a enviar
  res              : RespuestaConsultaFactuSistemaFacturacionType;    // Respuesta tras el envio

  HTTPRIO1          : THTTPRIO;

  j                : integer;

  direccion_envio,  estado  : string;

  eventos      : TEventosHttpPrio;
  eventosWebNode: TEventosWebNode;
begin
      consulta:=ConsultaFactuSistemaFacturacion.Create;

      consulta.Cabecera:=CabeceraConsultaSf.Create;
      consulta.Cabecera.ObligadoEmision:=ObligadoEmisionConsultaType.Create;
      consulta.Cabecera.ObligadoEmision.NombreRazon:=sesiones[sesion].inicio.emisor.NombreRazonEmisor;
      consulta.Cabecera.ObligadoEmision.NIF:=sesiones[sesion].inicio.emisor.nifEmisor;
      consulta.FiltroConsulta:=LRFiltroRegFacturacionType.Create;
      consulta.FiltroConsulta.PeriodoImputacion:=PeriodoImputacionType.Create;
      consulta.FiltroConsulta.PeriodoImputacion.Ejercicio:=resultado.Cabecera.ejercicio;
      consulta.FiltroConsulta.PeriodoImputacion.Periodo:=veriFactuPeriodo( resultado.Cabecera.periodo );

      if resultado.Cabecera.NumSerieFactura='' then
      begin
          consulta.FiltroConsulta.FechaExpedicionFactura.RangoFechaExpedicion.Desde:=verifactuFecha(datetoStr(resultado.Cabecera.dfecha));
          consulta.FiltroConsulta.FechaExpedicionFactura.RangoFechaExpedicion.Hasta:=verifactuFecha(datetoStr(resultado.Cabecera.hfecha));
      end
      else
      begin
          consulta.FiltroConsulta.NumSerieFactura:=resultado.Cabecera.NumSerieFactura;
      end;

      eventos:=TEventosHttpPrio.Create;

      eventos.fileNameBefore  :=sesiones[sesion].saveXMLenvio;
      eventos.fileNameAfter  :=sesiones[sesion].saveXMLResult;

      eventosWebNode:=TEventosWebNode.Create;
      eventosWebNode.sesion:=sesion;

      HTTPRIO1:=THTTPRIO.create(nil);
      HTTPRIO1.onBeforeExecute:=eventos.BeforeExecute;
      HTTPRIO1.onAfterExecute :=eventos.AfterExecute;

      // Cargar certificado del disco
      if ( pos('.PFX',uppercase(sesiones[sesion].inicio.nombreCertificado))<>0) or
        ( pos('.P12',uppercase(sesiones[sesion].inicio.nombreCertificado))<>0) then
          HTTPRIO1.HTTPWebNode.onBeforePost:=eventosWebNode.WebNodeBeforePost;

      // --> envío pre-produccion:  'https://prewww1.aeat.es/wlpl/TIKE-CONT/ws/SistemaFacturacion/VerifactuSOAP';
      try
          // Cargar certificado del almacen
          if ( pos('.PFX',uppercase(sesiones[sesion].inicio.nombreCertificado))=0) and
            ( pos('.P12',uppercase(sesiones[sesion].inicio.nombreCertificado))=0) then
            HTTPRIO1.HTTPWebNode.ClientCertificate.SerialNum := Buscar_Certificado_SERIAL( sesiones[sesion].inicio.nombreCertificado );  // coloca el certificado

          direccion_envio :=sesiones[sesion].inicio.direccion_envio;

          res:=  RespuestaConsultaFactuSistemaFacturacionType.Create;
          res:=  GetsfPortTypeVerifactu( false, direccion_envio , HTTPRIO1 ).ConsultaFactuSistemaFacturacion( consulta ); // Enviarlo !

          // resultado del envio:
          resultado.ConDatos:=(res.ResultadoConsulta=ResultadoConsultaType.ConDatos);
          resultado.error  :=false;
          resultado.errorDes:='';


          procesarConsulta(res,resultado );
      except
      on E:Exception do
      begin
          resultado.ConDatos:=false;
          resultado.error:=true;
          resultado.errorDes:=Format('(%s)-%s',[E.ClassName, E.Message]);
          result:=false;
          exit;
      end;

            // Finalmente:
            // HTTPRIO1.free;  //<- no puede ser destruido con NIL como constructor
            //eventos.Free;
      end;
      result:=true;
end;


seccion_31 05-02-2025 14:26:51

Voy a incorporarle el tema de las facturas exentas

Con lo que ya hay programado, para el desglose del IVA necesito saber el texto de las diferentes leyes, para al menos ajustar la clave de exencion automatica para las de exportacion UE, fuera de UE, y canarias correctamente.

E1 Exenta por el artículo 20
E2 Exenta por el artículo 21 (canarias, y fuera la UE)
E3 Exenta por el artículo 22
E4 Exenta por los artículos 23 y 24
E5 Exenta por el artículo 25 (exportacion a la UE)
E6 Exenta por otros

Me gustaria saber un pequeño texto resumen de los articulos.

A ver si alguien me puede aclarar este tema x favor.

Slds !

ramherfer 05-02-2025 17:18:11

Cita:

Empezado por seccion_31 (Mensaje 561742)
ramherfer

sustituye esta funcion: uVerifactuFuncs y recompila el servidor B10

Código:

function consultar(sesion:integer; var resultado:TConsultaResultado):boolean;
var
  consulta          : ConsultaFactuSistemaFacturacion;                  // Objeto a enviar
  res              : RespuestaConsultaFactuSistemaFacturacionType;    // Respuesta tras el envio

  HTTPRIO1          : THTTPRIO;

  j                : integer;

  direccion_envio,  estado  : string;

  eventos      : TEventosHttpPrio;
  eventosWebNode: TEventosWebNode;
begin
      consulta:=ConsultaFactuSistemaFacturacion.Create;

      consulta.Cabecera:=CabeceraConsultaSf.Create;
      consulta.Cabecera.ObligadoEmision:=ObligadoEmisionConsultaType.Create;
      consulta.Cabecera.ObligadoEmision.NombreRazon:=sesiones[sesion].inicio.emisor.NombreRazonEmisor;
      consulta.Cabecera.ObligadoEmision.NIF:=sesiones[sesion].inicio.emisor.nifEmisor;
      consulta.FiltroConsulta:=LRFiltroRegFacturacionType.Create;
      consulta.FiltroConsulta.PeriodoImputacion:=PeriodoImputacionType.Create;
      consulta.FiltroConsulta.PeriodoImputacion.Ejercicio:=resultado.Cabecera.ejercicio;
      consulta.FiltroConsulta.PeriodoImputacion.Periodo:=veriFactuPeriodo( resultado.Cabecera.periodo );

      if resultado.Cabecera.NumSerieFactura='' then
      begin
          consulta.FiltroConsulta.FechaExpedicionFactura.RangoFechaExpedicion.Desde:=verifactuFecha(datetoStr(resultado.Cabecera.dfecha));
          consulta.FiltroConsulta.FechaExpedicionFactura.RangoFechaExpedicion.Hasta:=verifactuFecha(datetoStr(resultado.Cabecera.hfecha));
      end
      else
      begin
          consulta.FiltroConsulta.NumSerieFactura:=resultado.Cabecera.NumSerieFactura;
      end;

      eventos:=TEventosHttpPrio.Create;

      eventos.fileNameBefore  :=sesiones[sesion].saveXMLenvio;
      eventos.fileNameAfter  :=sesiones[sesion].saveXMLResult;

      eventosWebNode:=TEventosWebNode.Create;
      eventosWebNode.sesion:=sesion;

      HTTPRIO1:=THTTPRIO.create(nil);
      HTTPRIO1.onBeforeExecute:=eventos.BeforeExecute;
      HTTPRIO1.onAfterExecute :=eventos.AfterExecute;

      // Cargar certificado del disco
      if ( pos('.PFX',uppercase(sesiones[sesion].inicio.nombreCertificado))<>0) or
        ( pos('.P12',uppercase(sesiones[sesion].inicio.nombreCertificado))<>0) then
          HTTPRIO1.HTTPWebNode.onBeforePost:=eventosWebNode.WebNodeBeforePost;

      // --> envío pre-produccion:  'https://prewww1.aeat.es/wlpl/TIKE-CONT/ws/SistemaFacturacion/VerifactuSOAP';
      try
          // Cargar certificado del almacen
          if ( pos('.PFX',uppercase(sesiones[sesion].inicio.nombreCertificado))=0) and
            ( pos('.P12',uppercase(sesiones[sesion].inicio.nombreCertificado))=0) then
            HTTPRIO1.HTTPWebNode.ClientCertificate.SerialNum := Buscar_Certificado_SERIAL( sesiones[sesion].inicio.nombreCertificado );  // coloca el certificado

          direccion_envio :=sesiones[sesion].inicio.direccion_envio;

          res:=  RespuestaConsultaFactuSistemaFacturacionType.Create;
          res:=  GetsfPortTypeVerifactu( false, direccion_envio , HTTPRIO1 ).ConsultaFactuSistemaFacturacion( consulta ); // Enviarlo !

          // resultado del envio:
          resultado.ConDatos:=(res.ResultadoConsulta=ResultadoConsultaType.ConDatos);
          resultado.error  :=false;
          resultado.errorDes:='';


          procesarConsulta(res,resultado );
      except
      on E:Exception do
      begin
          resultado.ConDatos:=false;
          resultado.error:=true;
          resultado.errorDes:=Format('(%s)-%s',[E.ClassName, E.Message]);
          result:=false;
          exit;
      end;

            // Finalmente:
            // HTTPRIO1.free;  //<- no puede ser destruido con NIL como constructor
            //eventos.Free;
      end;
      result:=true;
end;


Funciona perfectamente con fichero de certificado.pfx. He integrado en la aplicación los dos metodos de certificación, para que se utilice el que más convenga, aunque con fichero pfx o p12 implica menos dependencias de otros componentes, por lo tanto menos trabajo de implantación de la versión. Yo al arrancar la aplicación verifico la fecha de vencimiento del certificado para lanzar un aviso cuando quedan menos de 60 días. Esto utilizando el nombre del certificado y capicom. Voy a ver la forma de hacerlo con el pfx.

seccion_31 05-02-2025 21:02:43

ya tengo implementado por decir algo las facturas exentas, añadiendo un campo al desglose de iva, con el identificador de la exencion, pero ...

hasta aqui llegamos, porque no me aclaro con el valor ClaveRegimen (mis conocimientos fiscales son muy limitados)

Si no estoy equivocado:

Si la exencion es la E2 ClaveRegimen va a 02. exportacion ¿pero siempre debe tomar ese valor? ¿la E2 solo se usa para exportacion fuera de la UE? (o canarias)
Si la exencion es la E5 ClaveRegimen va a 01. factura UE ¿pero siempre debe tomar ese valor? ¿la E5 solo se usa para facturas UE?

Con E6 (otra) puede ir a ClaveRegimen 01, pero ¿se puede calcular ClaveRegimen segun el valor de la exencion?

¿
E1
E3
E4
?

Y aqui me paro hasta ver x favor, quien nos puede aclarar este tema.

Saludos !


La franja horaria es GMT +2. Ahora son las 05:06:20.

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