Integrar VeriFactu en Odoo

· Equipo Factuneo

Conecta la facturación de Odoo con VeriFactu llamando a la API al validar cada factura: un módulo ligero que emite el registro y guarda la huella y el QR, sin tocar el core de Odoo.

Odoo genera las facturas; Factuneo las convierte en registros VeriFactu (huella, QR y envío a la AEAT) con una llamada HTTP. No reescribes la contabilidad de Odoo: enganchas la emisión al validar la factura.

La idea

Cuando una factura pasa a Publicada en Odoo (account.move.action_post), tu módulo llama a la API de Factuneo y guarda en la factura la huella, el QR y el estado.

1. API key

Guárdala en los parámetros del sistema (Ajustes → Técnico → Parámetros del sistema), p. ej. factuneo.api_key. Nunca en el código.

2. Alta del emisor (una vez por empresa)

import requests
BASE = "https://factuneo.es/api/v1"

requests.post(f"{BASE}/emisores",
    headers={"x-api-key": api_key},
    json={"nif": "B12345678", "nombreRazon": "Mi Empresa SL", "certMode": "PROPIO"})

3. Un módulo que engancha el post de la factura

from odoo import models
import requests

BASE = "https://factuneo.es/api/v1"

class AccountMove(models.Model):
    _inherit = "account.move"

    def action_post(self):
        res = super().action_post()
        for move in self.filtered(lambda m: m.move_type == "out_invoice"):
            move._enviar_verifactu()
        return res

    def _enviar_verifactu(self):
        api_key = self.env["ir.config_parameter"].sudo().get_param("factuneo.api_key")
        payload = {
            "emisorNif": (self.company_id.vat or "").replace("ES", ""),
            "numeroSerie": self.name,
            "fechaExpedicion": str(self.invoice_date),
            "tipoFactura": "F1",
            "nombreRazonEmisor": self.company_id.name,
            "descripcionOperacion": self.invoice_origin or "Venta",
            "baseImponible": self.amount_untaxed,
            "cuotaIva": self.amount_tax,
            "importeTotal": self.amount_total,
            "destinatarios": [{"nombreRazon": self.partner_id.name,
                               "nif": (self.partner_id.vat or "").replace("ES", "")}],
            "desglose": [{
                "claveRegimen": "01",
                "calificacionOperacion": "S1",
                "tipoImpositivo": 21,
                "baseImponible": self.amount_untaxed,
                "cuotaRepercutida": self.amount_tax,
            }],
        }
        r = requests.post(f"{BASE}/invoices", headers={"x-api-key": api_key}, json=payload, timeout=30)
        data = r.json()
        # Guarda data["huella"], data["qr"] y data["estado"] en campos de la factura

4. Estado por webhook

Registra una URL de webhook en Factuneo y actualiza el estado de la factura en Odoo cuando la AEAT responde (aceptado/rechazado), en vez de sondear.

La documentación tiene todos los campos y los modos de certificado (Propio/Representado). Si gestionas muchas empresas, mira la guía para gestorías.

← Volver al blog · Factuneo