Schemas
OpenFactu usa multi-schema en PostgreSQL:
- public — Tablas globales (usuarios, tenants, plugins, geodatos)
- tenant_* — Un schema por empresa con todas las tablas de negocio
Tablas del schema publico
Tenant (Empresas)
| Campo | Tipo | Descripcion |
|---|
id | PK | UUID |
name | UNIQUE | Nombre de la empresa |
schemaName | UNIQUE | Nombre del schema PostgreSQL |
config | TEXT | JSON con configuracion |
createdAt | TIMESTAMP | |
updatedAt | TIMESTAMP | |
GlobalUser (Usuarios)
| Campo | Tipo | Descripcion |
|---|
id | PK | UUID |
email | UNIQUE | |
username | UNIQUE | |
password | TEXT | Hash bcrypt |
role | TEXT | USER / ADMIN / SUPERUSER |
tenantId | FK Tenant | Legacy, usar membresías |
permissions | TEXT | JSON de permisos granulares |
createdAt | TIMESTAMP | |
updatedAt | TIMESTAMP | |
UserTenantMembership (Membresías)
| Campo | Tipo | Descripcion |
|---|
id | PK | |
userId | FK GlobalUser | |
tenantId | FK Tenant | |
role | TEXT | USER / ADMIN |
permissions | TEXT | JSON |
createdAt | TIMESTAMP | |
updatedAt | TIMESTAMP | |
| UNIQUE | (userId, tenantId) |
PluginField (Campos de plugins)
| Campo | Tipo | Descripcion |
|---|
id | PK | |
pluginId | TEXT | ID del plugin |
tableName | TEXT | Tabla destino |
fieldName | TEXT | Nombre (prefijo p_) |
fieldType | TEXT | TEXT / INTEGER / DECIMAL / BOOLEAN / JSONB |
label | TEXT | Etiqueta UI |
isManaged | BOOLEAN | |
createdAt | TIMESTAMP | |
PluginTable (Tablas de plugins)
| Campo | Tipo | Descripcion |
|---|
id | PK | |
pluginId | TEXT | |
tableName | TEXT | Nombre (prefijo pt_) |
definition | TEXT | JSON con columnas |
createdAt | TIMESTAMP | |
TenantPlugin (Activacion de plugins)
| Campo | Tipo | Descripcion |
|---|
id | PK | |
tenantId | FK Tenant | |
pluginId | TEXT | |
isActive | BOOLEAN | |
config | TEXT | JSON config del plugin |
activatedAt | TIMESTAMP | |
deactivatedAt | TIMESTAMP | |
| UNIQUE | (tenantId, pluginId) |
AuditLog (Auditoria)
| Campo | Tipo | Descripcion |
|---|
id | PK | |
tenantId | FK Tenant | |
entityType | TEXT | Item, SalesInvoice, etc. |
entityId | TEXT | |
action | TEXT | CREATE / UPDATE / DELETE |
userId | FK GlobalUser | |
oldValue | JSONB | Estado anterior |
newValue | JSONB | Estado nuevo |
createdAt | TIMESTAMP | |
Country (Paises)
| Campo | Tipo | Descripcion |
|---|
code | PK | ISO 3166-1 alpha-2 |
name | TEXT | Nombre local |
nameEn | TEXT | Nombre en ingles |
phonePrefix | TEXT | +34 |
currency | TEXT | EUR |
taxIdRegex | TEXT | Validacion NIF |
taxIdLabel | TEXT | Etiqueta (NIF/CIF) |
postalCodeRegex | TEXT | |
regionLabel | TEXT | Comunidad Autonoma |
subRegionLabel | TEXT | Provincia |
localityLabel | TEXT | Municipio |
Region, SubRegion, Locality
Jerarquia geografica: Pais → Region → Provincia → Municipio. Cada nivel tiene id, code, name y FK al nivel superior.
Tablas del schema de tenant
SystemConfig
| Campo | Tipo | Descripcion |
|---|
id | PK | |
key | UNIQUE | Ej: company_name, branding_color_primary |
value | TEXT | |
description | TEXT | |
updatedAt | TIMESTAMP | |
BusinessPartner (Socios)
| Campo | Tipo | Descripcion |
|---|
id | PK | |
code | UNIQUE | Auto-generado (prefijo del grupo) |
name | TEXT | Nombre/razon social |
nif | UNIQUE | NIF/CIF |
foreignName | TEXT | |
phone | TEXT | |
email | TEXT | |
website | TEXT | |
groupId | FK PartnerGroup | |
priceListId | FK PriceList | |
countryCode | TEXT | |
PartnerGroup
| Campo | Tipo | Descripcion |
|---|
id | PK | |
code | UNIQUE | CLI, PRV, MAY |
name | TEXT | |
codePrefix | TEXT | Prefijo auto-numeracion |
isCustomer | BOOLEAN | |
isVendor | BOOLEAN | |
PartnerAddress (Direcciones)
| Campo | Tipo | Descripcion |
|---|
id | PK | |
partnerId | FK BusinessPartner | |
name | TEXT | |
street | TEXT | |
city | TEXT | |
state | TEXT | |
zipCode | TEXT | |
countryCode | TEXT | |
type | TEXT | B (facturacion) / S (envio) |
isDefault | BOOLEAN | |
Item (Articulos)
| Campo | Tipo | Descripcion |
|---|
id | PK | |
code | UNIQUE | |
name | TEXT | |
description | TEXT | |
uomId | FK UnitsOfMeasure | |
categoryId | FK Category | |
taxGroupId | FK TaxGroup | |
manageBy | TEXT | N / B (lotes) / S (series) |
basePrice | DECIMAL(12,4) | |
stock | DOUBLE | |
minStock | DOUBLE | |
createdAt | TIMESTAMP | |
updatedAt | TIMESTAMP | |
ItemBatch (Lotes)
| Campo | Tipo | Descripcion |
|---|
id | PK | |
batchNum | TEXT | Numero de lote |
itemId | FK Item | |
quantity | DOUBLE | |
expiryDate | DATE | |
ItemSerial (Series)
| Campo | Tipo | Descripcion |
|---|
id | PK | |
serialNum | UNIQUE | |
itemId | FK Item | |
status | TEXT | A (activo) / I (inactivo) |
Category (Categorias)
| Campo | Tipo | Descripcion |
|---|
id | PK | |
name | TEXT | |
codePrefix | TEXT | |
parentId | FK Category | Para jerarquia |
UnitsOfMeasure
| Campo | Tipo | Descripcion |
|---|
id | PK | |
code | UNIQUE | UD, KG, L, M, CJ, BL, H |
name | TEXT | |
baseValue | DECIMAL(12,4) | Factor base (default 1) |
baseUomId | FK UOM | Para conversiones |
ItemAlternativeUom
| Campo | Tipo | Descripcion |
|---|
id | PK | |
itemId | FK Item | |
uomId | FK UOM | |
factor | DECIMAL(12,4) | Ej: 12 (1 caja = 12 uds) |
Warehouse (Almacenes)
| Campo | Tipo | Descripcion |
|---|
id | PK | |
name | TEXT | |
location | TEXT | |
isDefault | BOOLEAN | |
WarehouseZone (Zonas)
| Campo | Tipo | Descripcion |
|---|
id | PK | |
name | TEXT | |
description | TEXT | |
warehouseId | FK Warehouse | |
ItemWarehouseStock
| Campo | Tipo | Descripcion |
|---|
itemId | FK Item | |
warehouseId | FK Warehouse | |
stock | DOUBLE | |
| UNIQUE | (itemId, warehouseId) |
ItemZoneStock
| Campo | Tipo | Descripcion |
|---|
itemId | FK Item | |
warehouseId | FK Warehouse | |
zoneId | FK Zone | |
stock | DOUBLE | |
| UNIQUE | (itemId, warehouseId, zoneId) |
TaxGroup (Impuestos)
| Campo | Tipo | Descripcion |
|---|
id | PK | |
code | UNIQUE | IVA0, IVA4, IVA10, IVA21 |
rate | DECIMAL(5,2) | Porcentaje |
PriceList / ItemPrice
Lista de precios con precio por articulo. Cada socio puede tener una lista asignada.
AccountingPeriod (Periodos)
| Campo | Tipo | Descripcion |
|---|
id | PK | |
code | UNIQUE | |
name | TEXT | |
startDate | DATE | |
endDate | DATE | |
status | TEXT | O (abierto) / C (cerrado) |
DocumentSeries (Series)
| Campo | Tipo | Descripcion |
|---|
id | PK | |
name | UNIQUE | |
docType | TEXT | SINV, PINV, SDN, PDN, SO, PO |
prefix | TEXT | FA, FC, AL, AC |
suffix | TEXT | |
firstNumber | INT | |
nextNumber | INT | |
periodId | FK Period | |
isDefault | BOOLEAN | |
DocumentTemplate (Plantillas PDF)
| Campo | Tipo | Descripcion |
|---|
id | PK | |
docType | TEXT | |
name | TEXT | |
html | TEXT | HTML con Handlebars |
isDefault | BOOLEAN | |
Documentos de venta
SalesOrder (Pedido de venta)
| Campo | Tipo | Descripcion |
|---|
id | PK | |
seriesId | FK Series | |
docNum | INT | Numero de documento |
periodId | FK Period | |
partnerId | FK Partner | |
date | DATE | |
status | TEXT | O / P / C / X |
warehouseId | FK Warehouse | |
subtotal | DECIMAL(15,4) | |
taxTotal | DECIMAL(15,4) | |
total | DECIMAL(15,4) | |
taxBreakdown | JSON | Desglose IVA |
SalesDeliveryNote (Albaran de venta)
Mismos campos que SalesOrder mas orderId (FK al pedido base). Al crear, descuenta stock.
SalesInvoice (Factura de venta)
Mismos campos. Estados: D (borrador) → O (asentada) / X (cancelada).
Lineas de documento
Todas las lineas de documento (SalesOrderLine, SalesDeliveryNoteLine, SalesInvoiceLine) comparten:
| Campo | Tipo | Descripcion |
|---|
id | PK | |
lineNum | INT | |
itemId | FK Item | |
quantity | DECIMAL(12,4) | |
price | DECIMAL(15,4) | |
taxGroupId | FK TaxGroup | |
lineTotal | DECIMAL(15,4) | |
warehouseId | FK Warehouse | |
zoneId | FK Zone | |
uomId | FK UOM | |
uomFactor | DECIMAL(12,4) | |
baseType | TEXT | SO, SDN, etc. |
baseId | TEXT | ID del doc base |
pluginData | JSONB | |
Lotes de linea (LineBatches)
| Campo | Tipo |
|---|
id | PK |
lineId | FK |
batchNum | TEXT |
quantity | DOUBLE |
expiryDate | DATE |
Documentos de compra
PurchaseOrder, PurchaseDeliveryNote, PurchaseInvoice
Estructura identica a los documentos de venta. Los albaranes de compra suman stock. Las facturas de compra cierran albaranes.
Tipos de referencia: PO (pedido) → PDN (albaran) → PINV (factura).