Saltar al contenido principal
B2Brouter · Odoo 19 · Compliance

B2Brouter y Odoo: Facturae, VeriFactu y a quién le toca ser el emisor legal

Antes de integrar B2Brouter con Odoo hay que decidir algo que no es técnico: qué sistema expide la factura. El artículo 9 del RD 1007/2023 deja poco margen, y esa decisión determina el resto de la arquitectura.

B2Brouter es una red de envío de documentos electrónicos, no tu sistema de facturación. Parece obvio y no lo es: esa frase decide qué puedes delegar y qué se queda en Odoo. Con VERI*FACTU, el sistema que expide la factura tiene obligaciones que no se cumplen mandando un XML a un tercero, y el reglamento lo dice con hora.

Qué resuelve B2Brouter y qué no

Es una plataforma de intercambio de documentos electrónicos: punto de acceso Peppol, FACe en España, SDI en Italia, Chorus Pro en Francia, KSeF en Polonia, ZATCA y MyInvois fuera de Europa. Para España añade VERI*FACTU, SII y TicketBAI. Técnicamente, una API REST con una cabecera de autenticación (X-B2B-API-Key), versionado por fecha (X-B2B-API-Version, hoy 2026-06-26) y todo colgando de /accounts/{id}/…; su especificación OpenAPI pública declara 56 rutas y 81 operaciones.

Lo que sí te quita de encima es el certificado: está dado de alta como colaborador social en la gestión tributaria, así que para remitir a la AEAT basta su clave de API. Lo que no te quita es la numeración de tus facturas, las rectificativas, el calendario fiscal y —la importante— la condición de emisor.

Quién es el emisor legal

El Real Decreto 1007/2023 llama sistema informático de facturación al conjunto de hardware y software utilizado para expedir facturas. No al que las transporta. Y el artículo 9, entero, dice esto:

«Los sistemas informáticos de facturación que sean utilizados por los obligados tributarios a que se refiere el artículo 3 de este Reglamento, deberán generar automáticamente un registro de facturación de alta de forma simultánea o inmediatamente anterior a la expedición de cada factura.»

Artículo 9 del Reglamento aprobado por el Real Decreto 1007/2023 (BOE-A-2023-24840).

Simultánea o inmediatamente anterior. No hay «inmediatamente después», ni «esa misma noche», ni «cuando el cron sincronice». Si Odoo valida la factura a las 11:04 y un proceso nocturno la vuelca a las 23:00 para que un tercero genere el registro, el diseño está mal, aunque el XML acabe llegando a la AEAT.

Delegar se puede: el artículo 6 permite que las obligaciones «podrán cumplirse materialmente por el destinatario de la operación o por un tercero», pero añade que eso «no exime a los obligados tributarios… de la responsabilidad del cumplimiento». Puedes delegar el trabajo; la responsabilidad, no.

La consecuencia práctica es una sola: la factura debe nacer y numerarse en un único sitio, y el registro debe generarse en ese mismo acto. Si Odoo es donde se valida la factura, Odoo es el emisor. Lo demás es transporte.

Qué tiene que quedarse en Odoo

  • La numeración y las series. Un número asignado en dos sistemas es un incidente esperando fecha.
  • La inmutabilidad. El artículo 8.2.a) exige que cualquier corrección se haga «mediante al menos un registro de facturación adicional posterior». En Odoo, «restablecer a borrador» sobre una factura registrada deja de ser una opción.
  • La trazabilidad. Los artículos 1 y 8.1 piden integridad, conservación, trazabilidad e inalterabilidad. Eso es un registro de eventos, no un log que rota cada siete días.
  • La declaración responsable. El artículo 13 exige que conste «por escrito y de modo visible en el propio sistema informático en cada una de sus versiones», y se la atribuye al productor del sistema. Si quien expide es Odoo con tus módulos, habla de ese conjunto.

El precio de equivocarse no es teórico: el artículo 201 bis de la Ley General Tributaria sanciona con 50.000 € por ejercicio la mera tenencia de sistemas de facturación no certificados cuando deban estarlo. La disposición final cuarta del real decreto fija las fechas: contribuyentes del Impuesto sobre Sociedades antes del 1 de enero de 2027; el resto, antes del 1 de julio de 2027.

Registro de eventos de un SIF en Odoo 19 con el alta del sistema y la declaración responsable de la versión
Registro de eventos de una instalación nueva en Odoo 19: alta del sistema y declaración responsable de esa versión.

Facturae, FACe y el B2B privado: tres caminos distintos

Facturae y FACe son el sector público. La Ley 25/2013 exige «un formato estructurado» firmado con «firma electrónica avanzada basada en un certificado reconocido» (art. 5) y crea el punto general de entrada (art. 6). En la práctica el problema nunca es el formato, son los tres códigos DIR3 —oficina contable, órgano gestor y unidad tramitadora—: si falta uno, rechaza el punto de entrada, no el cliente. En la API de B2Brouter son cin1, cin2 y cin3 con esquema 8014, transporte es.face y formato xml.facturae.3.2; si el XML importado ya cumple lo mandan tal cual, y si viene sin firmar lo firman ellos.

La factura electrónica B2B es otra cosa y todavía no ha empezado. El Real Decreto 238/2026 (BOE-A-2026-7295) fija el modelo EN 16931 y cuatro sintaxis: CII, UBL, EDIFACT y Facturae. El plazo no cuenta desde el reglamento sino desde la orden ministerial de la Solución Pública de Facturación Electrónica —un año para quien factura más de 8 millones, dos para el resto—, y el reloj no arranca hasta que esa orden entre en vigor.

VERI*FACTU ni es un formato ni es un envío al cliente: es un registro paralelo de cada factura, generado al expedirla. Y los dos regímenes no se excluyen: el artículo 2 bis.6 de la Ley 56/2007 exige que los programas de factura electrónica cumplan también el artículo 29.2.j) de la Ley General Tributaria, que es de donde cuelga VERI*FACTU. Se acumulan. Si vienes de cero, empieza por qué es VERI*FACTU y cómo cumplirlo con Odoo.

Qué se envía desde Odoo y qué vuelve

Hacia fuera va la factura como JSON, con numeración, fechas, impuestos, importes y los códigos de enrutado del destinatario. El detalle que más tiempo cuesta es cuadrar los céntimos: si dejas que la plataforma recalcule las bases desde cantidad × precio, una línea con descuento acabará saliendo con un céntimo de diferencia respecto a Odoo.

Hacia dentro vuelve el estado, y aquí está el error más repetido. La API distingue 22 estados de lectura y solo 9 que puedas fijar tú:

EstadoQué significa de verdadQuién lo pone
sentEl documento salió por el transporteLa red
registeredHay respuesta de una administración tributariaLa administración
acceptedAlguien del otro lado lo dio por buenoEl cliente
refused / errorRechazo, o fallo de envíoAmbos lados

Colapsarlos en un único booleano «enviado» es cómodo el primer día y caro el día que alguien pregunta, ocho meses después, si aquella factura llegó a la administración. Y un matiz que solo se aprende en producción: una respuesta correcta no significa transmitido. La llamada de envío devuelve 204 y la entrega sigue siendo asíncrona; y hay respuestas de 200 que traen errores dentro, en un errors[] que nadie mira. La vuelta va por webhook firmado con HMAC-SHA256, sin política de reintentos documentada: un webhook perdido es un estado que nunca se actualiza, así que hacen falta deduplicación y un cron de sondeo de respaldo.

La huella encadenada y por qué se calcula mal

El registro de alta no es la factura: son ocho campos encadenados con el anterior mediante una huella SHA-256. El artículo 13.1 de la Orden HAC/1177/2024 lista su orden —NIF del emisor, número y serie, fecha de expedición, tipo de factura, cuota total, importe total, huella anterior y fecha-hora-huso—, pero el apartado 2 remite «el algoritmo y codificación» a un documento técnico de la sede de la AEAT. El BOE te da una lista ordenada; no te da el formato.

Si te quedas en el BOE, lo natural es concatenar los ocho valores y aplicar SHA-256. Es exactamente lo que hicimos en nuestro propio módulo de VERI*FACTU, y está mal. La especificación de la AEAT exige pares etiquetados clave=valor unidos por &:

IDEmisorFactura=B12345678&NumSerieFactura=FA/2026/0001&FechaExpedicionFactura=15-06-2026
&TipoFactura=F1&CuotaTotal=21.00&ImporteTotal=121.00&Huella=
&FechaHoraHusoGenRegistro=2026-06-15T11:04:33+02:00

SHA-256 en hexadecimal y mayúsculas sobre esa cadena. Y ojo al penúltimo campo: en el primer registro, Huella va vacío. Nosotros lo habíamos sembrado con 64 ceros, que es lo que uno escribe por instinto. Fue el segundo fallo, encontrado dos días después del primero.

Qué lo delataba: nada

La suite estaba verde. Un fallo de huella no se parece a un fallo normal: cada huella sigue siendo un hexadecimal de 64 caracteres válido, la cadena enlaza consigo misma sin un hueco, y la verificación de integridad del módulo pasa —porque recalcula con la misma fórmula equivocada—. El test que tenía que haberlo cazado era este:

def test_genesis_huella_anterior(self):
    genesis = self.cadena.genesis_id
    if genesis:
        self.assertEqual(genesis.huella_anterior, '0' * 64,
                         'Genesis record must have all-zeros huella_anterior')

Dos defectos en cuatro líneas: el if genesis: lo convierte en un aprobado automático cuando no hay registro génesis, y la constante que comprueba es precisamente la equivocada. Un test vacuo que además codificaba el error. Ahora es así:

def test_genesis_huella_anterior(self):
    self._make_invoice()
    genesis = self.cadena.genesis_id
    self.assertTrue(genesis, 'Expected the first posted invoice to become the genesis record')
    self.assertEqual(genesis.huella_anterior, '',
                     'Genesis record must have empty huella_anterior per AEAT spec')

La regla que quedó: un test que se cae si borras el código que protege es un test; el resto es decoración.

Contrasta tu huella con el ejemplo resuelto que publica la AEAT antes de emitir la primera factura: el artículo 8.2.a) impide reescribir registros ya generados, así que una cadena mal calculada no se arregla, se arrastra.

Lista vacía de registros de facturación en Odoo 19 con las columnas número, número de serie, fecha de expedición, tipo de factura y estado
El registro de facturación en Odoo 19 recién instalado: las columnas son las del reglamento y, como avisa la propia lista vacía, cada fila nace al validar una factura, no al enviarla.

Cuándo B2Brouter te sobra y cuándo te ahorra meses

  • Te ahorra meses si envías a más de un país o red, tienes clientes del sector público con códigos DIR3, no quieres custodiar un certificado cualificado o quieres una capa que ya hable las cuatro sintaxis de Crea y Crece.
  • Te sobra si facturas solo en España, sin administraciones como clientes, y lo único que te obliga es VERI*FACTU: ahí un módulo que encadene y remita desde Odoo hace el trabajo sin añadir un salto de red, un coste por transacción ni un segundo sitio donde mirar cuando algo falla.

La incompatibilidad que nadie te cuenta

Si eliges B2Brouter para VERI*FACTU, no puedes mantener a la vez tu propia cadena en Odoo. El ajuste es de cuenta, no de factura: una vez activo, encadena todas las facturas de esa cuenta. Y si importas un XML que ya trae huella, la descartan; su documentación lo dice sin rodeos: esa información se ignora y su sistema hace el proceso de encadenado igualmente. Es la decisión correcta —una cadena con dos autores no es una cadena—, pero implica que las dos soluciones se excluyen por empresa: si conviven, la AEAT recibe dos series de registros para las mismas facturas.

En el conector que construimos contra su API eso es una exclusión dura: o una o la otra, nunca las dos. El módulo lleva una única suite de 778 tests, la misma en las tres ramas, y cada una se cierra corriéndola contra un Odoo real de su versión: 19, 18 y 17. El camino de envío está ejercitado contra su entorno de pruebas hasta registered, con los caminos de rechazo y de error incluidos. Por ahí apareció que el módulo ni siquiera se instalaba en la 17: un xpath heredado apuntaba a la plantilla kanban card, el nombre de la 18 en adelante —la 17 la llama kanban-box—, y un xpath que no encuentra su destino tumba la instalación entera. La rama 17 arrancó cero tests. Un módulo que compila no es un módulo que instala.

Conectar tu software con OdooCómo trabajamos con partners tecnológicos que necesitan un conector de Odoo.Integraciones y automatizaciónIntegraciones fiscales y de marketplace sobre Odoo 17, 18 y 19.Qué es VERI*FACTU y cómo cumplirloEl reglamento, los plazos y qué mirar en tu Odoo antes de 2027.e-Factura y SAF-T de RumaniaEl mismo problema en otro país: registro, envío y estado de vuelta.

Preguntas frecuentes

¿B2Brouter sustituye a un módulo de VERI*FACTU en Odoo?

Lo sustituye como motor de encadenado y remisión, no como sistema emisor: el artículo 9 del RD 1007/2023 exige que el registro se genere de forma simultánea o inmediatamente anterior a la expedición, y quien expide sigue siendo Odoo. Además, las dos soluciones se excluyen por empresa.

¿Puedo enviar las facturas a B2Brouter con un cron nocturno?

Para el documento (Peppol, FACe, correo) sí, dentro del plazo de cada canal. Para el registro de VERI*FACTU no: el artículo 9 solo admite «simultánea o inmediatamente anterior» a la expedición.

¿Facturae y factura electrónica B2B son lo mismo?

No. Facturae firmada con firma electrónica avanzada es lo que exige la Ley 25/2013 para facturar a administraciones públicas. La factura electrónica B2B del RD 238/2026 admite cuatro sintaxis sobre el modelo EN 16931, y su plazo todavía no ha empezado a contar.

¿Qué estado debo guardar en Odoo?

Los tres por separado: transporte (sent), administración (registered) y cliente (accepted o refused). La API distingue 22 de lectura y solo 9 que se puedan fijar a mano.

¿Integras B2Brouter con Odoo?

Miramos tu numeración, tus series, el momento en que se genera el registro y los estados que vuelven, y te decimos qué se queda en Odoo y qué puede irse a la red. Reserva una llamada en Calendly o llámanos al +34 616 809 504.

Hablar con un ingeniero