Skip to content

Microsoft Excel (VBA)

El middleware de VeriFactu (SystemsFGH) es completamente agnóstico al lenguaje. Permite emitir facturas directamente desde hojas de cálculo o plantillas de Microsoft Excel usando Macros en VBA.

Guía de Integración Rápida

Estimado Autónomo o Desarrollador VBA: Muchas pymes generan sus facturas directamente desde plantillas de Excel. Con este script, un simple botón de "Enviar a AEAT" en tu hoja de cálculo desencadenará el proceso fiscal de VeriFactu de forma automática sin salir de Office.

Código de Ejemplo

  1. Abre tu Excel, pulsa ALT + F11 para abrir el editor VBA.
  2. Inserta un nuevo "Módulo" y pega este código.
  3. El motor O(1) funciona igual: Hace POST enviando los datos de las celdas, espera unos segundos y recupera el C.S.V para imprimirlo en tu factura.
vb
Attribute VB_Name = "VeriFactu_Demo_VBA"
' ============================================================================
' GUÍA DE INTEGRACIÓN RÁPIDA: VERI*FACTU MICRO-SERVICE VÍA MICROSOFT EXCEL (VBA)
' ============================================================================
' 
' Estimado Autónomo o Desarrollador VBA:
' Muchas pymes generan sus facturas directamente desde plantillas de Excel. 
' Con este script, un simple botón de "Enviar a AEAT" en tu hoja de cálculo
' desencadenará el proceso fiscal de VeriFactu automatizadamente sin salir de Office.
'
' INSTRUCCIONES DE USO:
' 1. Abre tu Excel, pulsa ALT + F11 para abrir el editor VBA.
' 2. Inserta un nuevo "Módulo" y pega este código.
' 3. El motor O(1) funciona igual: Hace POST enviando los datos de las celdas, 
'    espera unos segundos y recupera el C.S.V para imprimirlo en tu factura.
' ============================================================================

Sub EnviarFactura_VeriFactu()
    Dim http As Object
    ' Usamos la librería nativa de Windows (ServerXMLHTTP) que soporta requests en background
    Set http = CreateObject("MSXML2.ServerXMLHTTP.6.0")
    
    Dim base_url As String
    base_url = "http://127.0.0.1:8000"
    
    ' ========================================================================
    ' 1. CONSTRUCCIÓN DEL PAYLOAD DESDE LAS CELDAS
    ' ========================================================================
    ' Aquí extraeríamos los datos reales de las celdas, por ejemplo:
    ' Dim numFactura As String: numFactura = ActiveSheet.Range("B3").Value
    '
    ' Para la demo, usamos variables y lo ensamblamos como String (para no depender 
    ' de librerías JSON externas de terceros en Excel nativo).
    
    Dim emisor As String: emisor = "B12345678"
    Dim serie As String: serie = "EXC"
    Dim num As String: num = CStr(Int((999999 - 100000 + 1) * Rnd + 100000))
    Dim fecha As String: fecha = Format(Now, "dd/mm/yyyy")
    
    Dim payload As String
    payload = "{" & _
        """cabecera"": {" & _
            """emisor"": """ & emisor & """, " & _
            """numfactura"": """ & num & """, " & _
            """serie"": """ & serie & """, " & _
            """rectificativa"": ""N"", " & _
            """tipofacturarectificativa"": """", " & _
            """fecharectificada"": """", " & _
            """facturarectificada"": """", " & _
            """rectificativasustitucion"": """", " & _
            """facturaf3"": ""N"", " & _
            """numseriesustituidaf3"": """", " & _
            """fechafactsustituidaf3"": """", " & _
            """descripcionoperacion"": ""Factura via VBA Excel SDK"", " & _
            """eliminacion"": ""N"", " & _
            """tipodoc"": ""01"", " & _
            """pais"": ""ES"", " & _
            """nif"": ""B98765432"", " & _
            """nombre"": ""EMPRESA DEMO S.L."", " & _
            """fecha"": """ & fecha & """, " & _
            """base1"": ""100.00"", ""piva1"": ""21.00"", ""iva1"": ""21.00"", " & _
            """base2"": """", ""piva2"": """", ""iva2"": """", " & _
            """base3"": """", ""piva3"": """", ""iva3"": """", " & _
            """base4"": """", ""piva4"": """", ""iva4"": """", " & _
            """base"": ""100.00"", " & _
            """totaliva"": ""21.00"", " & _
            """total"": ""121.00""" & _
        "}, " & _
        """detalle"": {" & _
            """base"": [""100.00"", """", """", """"], " & _
            """piva"": [""21.00"", """", """", """"], " & _
            """iva"": [""21.00"", """", """", """"], " & _
            """precargo"": ["""", """", """", """"], " & _
            """recargo"": ["""", """", """", """"]" & _
        "}, " & _
        """metadata"": { ""insertar_en_db"": true }" & _
    "}"
    
    ' ========================================================================
    ' 2. ENVIAR INGESTA AL MICROSERVER LOCAL
    ' ========================================================================
    http.Open "POST", base_url & "/v1/ingesta", False
    http.setRequestHeader "Content-Type", "application/json"
    
    On Error GoTo ManejoErrorInternet
    http.Send payload
    On Error GoTo 0
    
    If http.Status < 200 Or http.Status >= 300 Then
        MsgBox "✖ Error de MicroServer (HTTP " & http.Status & "): " & vbCrLf & http.responseText, vbCritical, "VeriFactu Error"
        Exit Sub
    End If
    
    ' ========================================================================
    ' 3. POLLING (SONDEO) O(1) - ESPERANDO A LA AGENCIA TRIBUTARIA
    ' ========================================================================
    Application.StatusBar = "Enviando factura a AEAT... Por favor, espere."
    
    Dim check_url As String
    check_url = base_url & "/v1/check_status?emisor=" & emisor & "&serie=" & serie & "&num=" & num
    
    Dim i As Integer
    Dim statusTerminado As Boolean
    statusTerminado = False
    Dim respuestaFinal As String
    
    For i = 1 To 15
        ' Esperar 1 segundo para no saturar 
        Application.Wait (Now + TimeValue("0:00:01"))
        
        http.Open "GET", check_url, False
        http.Send
        
        If http.Status = 200 Then
            respuestaFinal = http.responseText
            ' La forma rudimentaria y nativa de parsear JSON en VBA sin dependencias es InStr
            If InStr(1, respuestaFinal, """status"":""pending""") = 0 Then
                statusTerminado = True
                Exit For
            End If
        End If
    Next i
    
    Application.StatusBar = False
    
    ' ========================================================================
    ' 4. PROCESAR RESPUESTA AEAT E INYECTARLA EN LA FACTURA
    ' ========================================================================
    If statusTerminado Then
        ' Ha llegado la respuesta definitiva
        ' Pequeño truco sucio de manipulación de cadenas para extraer el CSV
        Dim csvExtraido As String
        csvExtraido = ExtraerValorJSON(respuestaFinal, "csv")
        
        If csvExtraido <> "" Then
            ' Magia: ¡Inyectamos el código fiscal en tu plantilla de Excel automáticamente!
            ' ActiveSheet.Range("H15").Value = "C.S.V. VeriFactu:" & csvExtraido
            MsgBox "✔ Factura " & serie & "-" & num & " enviada con éxito a la AEAT." & vbCrLf & vbCrLf & _
                   "C.S.V. Recibido: " & csvExtraido, vbInformation, "VeriFactu Aceptado"
        Else
            MsgBox "Rechazado o sin CSV. Ver respuesta completa: " & vbCrLf & respuestaFinal, vbExclamation, "Atención"
        End If
    Else
       MsgBox "⏳ Tiempo de espera agotado de 15 segundos. La Agencia Tributaria va lenta." & vbCrLf & _
              "Tranquilo, tu factura está encapsulada a salvo en el Motor", vbExclamation, "Cola AEAT"
    End If
    
    Exit Sub

ManejoErrorInternet:
    MsgBox "No se pudo contactar con el MicroServer. Asegúrate de que VeriFactu está encendido.", vbCritical
End Sub

' Función auxiliar para extraer datos básicos limpiamente
Function ExtraerValorJSON(jsonString As String, clave As String) As String
    Dim posInicio As Long, posFin As Long
    Dim buscarClave As String
    buscarClave = """" & clave & """:"""
    
    posInicio = InStr(1, jsonString, buscarClave)
    If posInicio > 0 Then
        posInicio = posInicio + Len(buscarClave)
        posFin = InStr(posInicio, jsonString, """")
        If posFin > posInicio Then
            ExtraerValorJSON = Mid(jsonString, posInicio, posFin - posInicio)
            Exit Function
        End If
    End If
    ExtraerValorJSON = ""
End Function