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.