- BR-23, fatal «An Invoice line (BG-25) shall have an Invoiced quantity unit of measure code (BT-130).» La línea tiene que llevar unidad.
- BR-CL-23, fatal «Unit code MUST be coded according to the UN/ECE Recommendation 20 with Rec 21 extension» La unidad tiene que ser un código de la lista.
- PEPPOL-EN16931-R130, fatal «Unit code of price base quantity MUST be same as invoiced quantity.» Si el precio va por una cantidad base, su unidad es la misma que la de la línea.
Las dos primeras son de EN 16931 (Schematron validation-1.3.17). La tercera es de Peppol BIS (3.0.22) y XRechnung también la aplica.

De dónde saca Odoo el código
El código que Odoo escribe en el fichero sale de un sitio distinto según la versión:
- Odoo 17, 18 y 19: tiene una tabla que relaciona las unidades de Odoo (por su identificador externo) con códigos UN/ECE. Una unidad que has creado tú no está en la tabla y sale como C62, unidad.
- Odoo 20: cada unidad de medida tiene su propio campo de código UN/ECE, y es ese código el que va al fichero. Odoo lo pasa a mayúsculas, pero no lo compara con la lista.
BR-CL-23 salta cuando el código del fichero no está en la lista. En Odoo 20 basta un código mal escrito en la unidad de medida. En Odoo 17 a 19 la tabla siempre da un código de la lista, así que la regla solo salta si el código llega por otro camino, como un módulo que lo cambie.
Hay además un problema que ninguna regla ve: una unidad propia («palé», «caja de doce») que en Odoo 17 a 19 se convierte en C62 sin avisar. El fichero pasa BR-CL-23, porque C62 está en la lista, pero tu cliente recibe «unidades» donde tú vendías cajas.
Para quien recibe la factura, el código cuenta: su programa lo lee para casar la línea con su pedido y con la entrada de mercancía. Si pidió cajas y la factura dice unidades, la cantidad no cuadra con lo que recibió aunque el importe sea el mismo, y la factura se queda parada en su revisión.
Con nuestro módulo XRechnung y ZUGFeRD
El módulo trae su propia tabla de unidades de Odoo a códigos UN/ECE, editable, para que cada unidad tuya tenga su código en BT-130. Una unidad que no esté en esa tabla sale como C62, igual que en Odoo 17 a 19, y el único aviso queda en el registro del servidor, que no se ve desde la factura. Una línea sin unidad también sale como C62.

En Odoo 18, 19 y 20, con la suscripción a FlexigoTech Cloud, cada XRechnung y cada ZUGFeRD EN 16931 se valida con las reglas de KoSIT y un código fuera de la lista queda como BR-CL-23 en Validation Errors. En Odoo 17 la versión publicada no valida.
Qué revisar
- Mira qué unidad lleva la línea en el XML (atributo unitCode).
- En Odoo 20, abre la unidad de medida y pon su código UN/ECE.
- En Odoo 17, 18 y 19, si usas unidades propias, ten en cuenta que saldrán como C62. Con nuestro módulo, en cualquier versión, añade cada una a su tabla: las que falten también salen como C62.
- Si el precio va por cantidad base (por ejemplo, por cada cien unidades), que su unidad sea la misma que la de la línea.
- Genera el fichero otra vez y comprueba el atributo unitCode de cada línea antes de enviarlo.
Sigue leyendo
Comprobado en el código del módulo (versión 17.0 y 20.0) y en las fuentes enlazadas
Fuentes
- github.com/odoo/odoo/blob/6f00fdadb875342de2d14a179f25431f93cd63c9/addons/account_edi_ubl_
- github.com/odoo/odoo/blob/2982b5f44af03fae6a9888f20632c1cc19f623ba/addons/account_edi_ubl_
- github.com/odoo/odoo/blob/4d2d4b5895db70596863df941d9a1f0beeb117f8/addons/account_edi_ubl_
- github.com/odoo/odoo/blob/2fec20391a8a61ea3a3bf15e9f24d59dba910a8d/addons/account_edi_ubl_
- Código del módulo: flexigo_germany_xrechnung 20.0 (446f2f68): models/xrechnung_uom_mapping.py
- Código del módulo: flexigo_germany_xrechnung 20.0 (446f2f68): models/xrechnung_cloud.py
- Código del módulo: flexigo_germany_xrechnung 17.0 (ad05de8f): __manifest__.py
- github.com/itplr-kosit/xrechnung-schematron/releases/tag/v2.6.0
- github.com/ConnectingEurope/eInvoicing-EN16931/releases/tag/validation-1.3.17
- docs.peppol.eu/poacc/billing/3.0/rules/ubl-peppol/PEPPOL-EN16931-R130/
