Las aplicaciones de escritorio antiguas no desaparecen de la noche a la mañana. Muchas empresas siguen operando con software desarrollado hace décadas en Visual Basic 6, Delphi, FoxPro o incluso aplicaciones DOS adaptadas a Windows. Estos sistemas no están diseñados para consumir APIs REST modernas, pero necesitan cumplir con VeriFactu igual que cualquier otra solución de facturación.

La cuestión es cómo adaptarse sin reescribir decenas de miles de líneas de código que llevan años funcionando.

El problema técnico real

Las aplicaciones legacy tienen limitaciones arquitectónicas concretas:

Reescribir estas aplicaciones para integrar una API REST no es solo costoso, en la mayoría de casos el código fuente original ya no está disponible, el desarrollador original ya no trabaja en la empresa, o la aplicación está tan entrelazada con lógica de negocio crítica que modificarla es demasiado arriesgado.

La solución: ejecutables como puente de integración

La forma más práctica de conectar este tipo de aplicaciones con servicios modernos es usar un ejecutable intermedio que actúe como traductor. La aplicación antigua escribe datos en un formato que conoce (archivos de texto, XML, línea de comandos), llama al ejecutable, y este se encarga de la comunicación con la API.

Este patrón no es nuevo. Se usa en integraciones bancarias, EDI, y cualquier escenario donde los sistemas antiguos necesitan hablar con protocolos modernos.

Ejemplo de flujo de integración

[Aplicación legacy] 
    ↓ (escribe archivo XML o JSON con datos de factura)
[Archivo temporal: factura.json]
    ↓ (la app ejecuta el .exe con parámetros)
[Ejecutable VeriFactu]
    ↓ (lee el archivo, firma, envía a AEAT)
[API VeriFactu] → [AEAT]
    ↓ (respuesta)
[Archivo de respuesta: resultado.json]
    ↓ (la app legacy lee el resultado)
[Aplicación legacy procesa el resultado]

Implementación práctica

Paso 1: Preparar los datos desde la aplicación antigua

La aplicación legacy debe generar un archivo con los datos de la factura. El formato más sencillo es JSON, pero si la aplicación no puede generarlo, un archivo de texto estructurado o XML también funciona.

Ejemplo de archivo factura.json:

{
  "numero_factura": "2025/0042",
  "fecha": "2025-01-15",
  "cliente_nif": "B12345678",
  "base_imponible": 1000.00,
  "iva": 210.00,
  "total": 1210.00,
  "conceptos": [
    {
      "descripcion": "Servicios consultoría",
      "cantidad": 1,
      "precio_unitario": 1000.00
    }
  ]
}

Si la aplicación legacy está escrita en Visual Basic 6, el código para generar este archivo sería:

Private Sub GenerarArchivoFactura()
    Dim rutaArchivo As String
    Dim contenido As String
    
    rutaArchivo = App.Path & "\factura.json"
    
    contenido = "{" & vbCrLf
    contenido = contenido & "  ""numero_factura"": """ & txtNumFactura.Text & """," & vbCrLf
    contenido = contenido & "  ""fecha"": """ & Format(dtpFecha.Value, "yyyy-mm-dd") & """," & vbCrLf
    contenido = contenido & "  ""cliente_nif"": """ & txtNIF.Text & """," & vbCrLf
    contenido = contenido & "  ""base_imponible"": " & txtBase.Text & "," & vbCrLf
    contenido = contenido & "  ""iva"": " & txtIVA.Text & "," & vbCrLf
    contenido = contenido & "  ""total"": " & txtTotal.Text & vbCrLf
    contenido = contenido & "}"
    
    Open rutaArchivo For Output As #1
    Print #1, contenido
    Close #1
End Sub

Paso 2: Llamar al ejecutable

Una vez generado el archivo, la aplicación legacy ejecuta el .exe pasándole la ruta del archivo como parámetro:

Private Sub EnviarFacturaVeriFactu()
    Dim rutaExe As String
    Dim rutaFactura As String
    Dim comando As String
    
    rutaExe = App.Path & "\verifactu.exe"
    rutaFactura = App.Path & "\factura.json"
    
    comando = rutaExe & " enviar --archivo """ & rutaFactura & """ --output resultado.json"
    
    Shell comando, vbNormalFocus
End Sub

En aplicaciones Delphi, el equivalente sería:

procedure TFormFactura.EnviarFactura;
var
  comando: string;
  resultado: Cardinal;
begin
  comando := ExtractFilePath(Application.ExeName) + 
             'verifactu.exe enviar --archivo factura.json --output resultado.json';
  
  resultado := ShellExecute(Handle, 'open', PChar(comando), nil, nil, SW_SHOWNORMAL);
  
  if resultado <= 32 then
    ShowMessage('Error al ejecutar VeriFactu');
end;

Paso 3: Procesar la respuesta

El ejecutable escribe el resultado en un archivo (por ejemplo, resultado.json). La aplicación legacy lee este archivo para saber si el envío fue exitoso:

{
  "estado": "aceptada",
  "csv": "ABC123XYZ789",
  "fecha_envio": "2025-01-15T10:30:45Z",
  "codigo_aeat": "ACEPTADO"
}

Código VB6 para procesar la respuesta:

Private Function LeerRespuesta() As Boolean
    Dim rutaRespuesta As String
    Dim contenido As String
    Dim estadoInicio As Long
    Dim estadoFin As Long
    Dim estado As String
    
    rutaRespuesta = App.Path & "\resultado.json"
    
    Open rutaRespuesta For Input As #1
    contenido = Input$(LOF(1), 1)
    Close #1
    
    ' Parsing básico de JSON (en VB6)
    estadoInicio = InStr(contenido, """estado"": """) + 12
    estadoFin = InStr(estadoInicio, contenido, """")
    estado = Mid(contenido, estadoInicio, estadoFin - estadoInicio)
    
    If estado = "aceptada" Then
        LeerRespuesta = True
        MsgBox "Factura enviada correctamente a VeriFactu"
    Else
        LeerRespuesta = False
        MsgBox "Error al enviar factura"
    End If
End Function

Consideraciones técnicas

Si la aplicación legacy necesita esperar la respuesta antes de continuar, usa Shell con espera bloqueante o escribe un bucle que verifique la existencia del archivo de respuesta.

En VB6, puedes usar la API de Windows:

Private Declare Function WaitForSingleObject Lib "kernel32" _
    (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long

Private Declare Function OpenProcess Lib "kernel32" _
    (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, _
     ByVal dwProcessId As Long) As Long

Private Declare Function CloseHandle Lib "kernel32" _
    (ByVal hObject As Long) As Long

Private Sub EjecutarYEsperar(comando As String)
    Dim taskID As Long
    Dim hProcess As Long
    Const SYNCHRONIZE = &H100000
    
    taskID = Shell(comando, vbNormalFocus)
    hProcess = OpenProcess(SYNCHRONIZE, False, taskID)
    
    WaitForSingleObject hProcess, -1  ' Esperar indefinidamente
    CloseHandle hProcess
End Sub

Gestión de errores

El ejecutable debe devolver códigos de error claros. Y por su parte, la aplicación legacy debe verificar:

  1. Que el archivo de respuesta se haya generado
  2. Que el contenido sea válido
  3. Que el estado indique éxito o error específico

Seguridad

Los archivos temporales con datos fiscales no deben quedar expuestos. Opciones para lograrlo:

Logs y trazabilidad

El ejecutable debe generar logs de todas las operaciones. La aplicación legacy puede leer estos logs para realizar una depuración o auditoría posterior.

Alternativa: stdin/stdout

Si tu aplicación legacy puede capturar la salida estándar de procesos, puedes pasar los datos directamente sin archivos intermedios:

echo '{"numero_factura":"2025/0042",...}' | verifactu.exe enviar --stdin

Esto elimina archivos temporales y simplifica el flujo.

Mantenimiento a largo plazo

Este enfoque tiene ventajas de mantenimiento:

Si trabajas con aplicaciones de escritorio antiguas y necesitas integrar VeriFactu, puedes probar nuestra librería ejecutable de VerifactuAPI en el sandbox sin certificado digital y totalmente gratis.