Maqueta de varias naves logísticas pequeñas unidas por líneas cian, símbolo de un ERP multiempresa y multialmacén
Software / APIs

ERP Multiempresa y Multialmacén sin Duplicar Datos

Codezone
Codezone Empresa de Desarrollo Web y Software a Medida

Un ERP multiempresa y multialmacén sin datos duplicados usa una sola base de datos en la que cada registro operativo lleva la empresa a la que pertenece, los maestros que comparte el grupo se guardan una vez y la propia base de datos impide mezclar empresas y almacenes con claves compuestas y políticas por fila. Es el diseño que aplicamos en cada ERP multiempresa a medida en Madrid que desarrollamos.

El punto de partida suele ser un grupo con varias sociedades que ha crecido por partes: una instalación del ERP por empresa, el mismo artículo dado de alta tres veces con códigos distintos y los traspasos entre almacenes de sociedades distintas registrados a mano en los dos lados. Cerrar el mes exige exportar a Excel y cuadrar, y cada diferencia cuesta horas. Antes de rediseñar conviene revisar los procesos de cada empresa del grupo en Madrid para ver qué es común y qué no.

Al terminar sabrás qué datos compartir y cuáles separar, cómo modelar empresas y almacenes para que no se mezclen, cómo registrar un traspaso intercompany y cómo numerar documentos por empresa, con un esquema SQL probado. Es un enfoque que encaja con la arquitectura de un ERP propio por módulos y fases, que aquí ampliamos al caso de varias sociedades.

Qué es un ERP multiempresa y multialmacén

Es un ERP que gestiona varias sociedades, cada una con su NIF, su contabilidad y sus series de facturas, y varios almacenes por sociedad, desde una única instalación. Los usuarios trabajan en una o varias empresas según sus permisos, y la dirección obtiene informes por empresa y consolidados sin reconciliar exportaciones de cada sistema.

Qué datos se comparten y cuáles son de cada empresa

La decisión más importante es entidad por entidad. Compartir de más mezcla información que legalmente pertenece a sociedades distintas; compartir de menos vuelve a duplicar. Es la conversación que debería abrir cualquier proveedor antes de proponer pantallas, y uno de los criterios para elegir empresa de software en Madrid. Un reparto habitual es este:

  • Artículos: maestro compartido. Un SKU existe una vez para todo el grupo, con sus códigos de barras y unidades de medida.
  • Clientes y proveedores: ficha única por NIF y condiciones por empresa, como tarifas, formas de pago o límite de riesgo.
  • Tarifas y precios: por empresa, porque cada sociedad negocia y factura por separado.
  • Almacenes: cada uno pertenece a una sola empresa, que es la dueña contable del stock que contiene.
  • Series, impuestos y plan contable: siempre por empresa.
  • Usuarios: globales, con permisos asignados empresa por empresa.

El patrón que mejor funciona es una ficha global más una extensión por empresa. La dirección del cliente se corrige una vez y aparece igual en todas las sociedades, mientras que sus condiciones comerciales siguen separadas. Si además los comerciales trabajan en un CRM, decide qué sistema manda en esa ficha con los criterios del CRM que comparten los comerciales del grupo.

Varias naves logísticas con muelles de carga al atardecer, cada una de una empresa distinta del mismo grupo
Varias sociedades y varios almacenes pueden compartir un solo ERP sin duplicar artículos ni clientes

Una base de datos con company_id

Hay dos opciones técnicas: una base de datos por empresa o una sola base con una columna que identifica la empresa en cada tabla operativa, a menudo llamada company_id o empresa_id. La primera aísla mejor, pero obliga a sincronizar los maestros compartidos y hace caro cualquier informe consolidado. La segunda es la que recomendamos para un grupo, porque comparte maestros de forma natural y consolida con una consulta. Encaja con un monolito modular con un único esquema de datos por dominio.

El riesgo de la columna compartida es olvidar el filtro en una consulta y mostrar datos de otra sociedad. Por eso el filtro no debe depender solo del código de la aplicación. PostgreSQL permite definir políticas de acceso por fila en cada tabla: con ellas activadas, si no existe una política que lo permita, la tabla no devuelve ninguna fila. Es el mismo mecanismo que usamos para separar clientes en un portal donde cada cliente ve solo lo suyo, aplicado aquí a empresas.

Almacenes por empresa y claves compuestas

Un pedido de la empresa A no puede servirse desde un almacén de la empresa B sin pasar por una operación entre sociedades. Esa regla se puede comprobar en el código, pero es más robusto que la imponga la base de datos. Si el almacén tiene una restricción única sobre la pareja empresa y almacén, el pedido puede referenciar esa pareja con una clave foránea compuesta, que la documentación de restricciones de PostgreSQL admite siempre que las columnas referenciadas formen una clave primaria o única.

El mismo principio se aplica a ubicaciones, movimientos y reservas. El stock de cada almacén se sigue calculando desde un libro de movimientos, como contamos en el software de stock multialmacén en Madrid, con la empresa como una columna más que la base de datos valida.

Traspasos entre almacenes y entre empresas

Un traspaso entre dos almacenes de la misma empresa es un movimiento interno: sale de uno y entra en otro, sin factura. Entre empresas distintas es una compraventa, aunque la mercancía viaje en el mismo camión. La sociedad que envía vende y factura, y la que recibe compra y registra la entrada. La Ley 27/2014 del Impuesto sobre Sociedades establece en su artículo 18 que las operaciones entre entidades vinculadas, como las de un mismo grupo, se valoran por su valor de mercado, así que el precio de ese traspaso debe quedar documentado.

El ERP puede automatizar ambos lados: al confirmar el traspaso genera el pedido de venta en la empresa de origen y el de compra en la de destino, como en cualquier gestión de pedidos entre empresas del grupo en Madrid. La base de datos impide registrar un traspaso intercompany sin su pedido de compra.

CodeZone Pro Tip: haz que la base de datos impida mezclar empresa y almacén con claves compuestas
-- Maestro compartido por todo el grupo: un artículo existe una sola vez
CREATE TABLE articulos (id int PRIMARY KEY, sku text NOT NULL UNIQUE, nombre text NOT NULL);
CREATE TABLE empresas (id smallint PRIMARY KEY, nif text NOT NULL UNIQUE);
-- Cada almacén pertenece a una empresa; UNIQUE (empresa_id, id) permite exigir la pareja en otras tablas
CREATE TABLE almacenes (id int PRIMARY KEY, empresa_id smallint NOT NULL REFERENCES empresas,
  nombre text NOT NULL, UNIQUE (empresa_id, id));
CREATE TABLE pedidos (
  id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
  empresa_id smallint NOT NULL REFERENCES empresas,
  serie text NOT NULL, numero int NOT NULL, almacen_id int NOT NULL,
  UNIQUE (empresa_id, serie, numero), UNIQUE (empresa_id, id),            -- numeración propia por empresa
  FOREIGN KEY (empresa_id, almacen_id) REFERENCES almacenes (empresa_id, id)  -- imposible servir desde otra empresa
);
-- Traspaso entre almacenes: si cambia de empresa es intercompany y exige un pedido en cada lado
CREATE TABLE traspasos (
  id bigint GENERATED ALWAYS AS IDENTITY PRIMARY KEY, articulo_id int NOT NULL REFERENCES articulos,
  empresa_origen smallint NOT NULL, almacen_origen int NOT NULL,
  empresa_destino smallint NOT NULL, almacen_destino int NOT NULL,
  pedido_destino bigint,                                                -- pedido de compra de la empresa que recibe
  FOREIGN KEY (empresa_origen, almacen_origen) REFERENCES almacenes (empresa_id, id),
  FOREIGN KEY (empresa_destino, almacen_destino) REFERENCES almacenes (empresa_id, id),
  FOREIGN KEY (empresa_destino, pedido_destino) REFERENCES pedidos (empresa_id, id),
  CHECK (almacen_origen <> almacen_destino),
  CHECK (empresa_origen = empresa_destino OR pedido_destino IS NOT NULL)
);
-- Cada usuario ve solo las empresas que tiene asignadas en su sesión
ALTER TABLE pedidos ENABLE ROW LEVEL SECURITY;
CREATE POLICY solo_mis_empresas ON pedidos
  USING (empresa_id = ANY (string_to_array(current_setting('app.empresas', true), ',')::smallint[]));

Probamos el esquema con dos empresas y tres almacenes: la base de datos rechazó servir un pedido desde el almacén de otra sociedad, repetir un número de pedido dentro de la misma empresa, hacer un traspaso intercompany sin pedido de compra y usar como pedido de compra uno de la empresa equivocada. Un usuario con una sola empresa asignada vio solo sus pedidos, y sin empresas asignadas no vio ninguno. Para el negocio significa que un error de programación o de importación no puede descuadrar el stock ni la contabilidad entre sociedades, algo que abarata mantener el ERP con el paso de los años.

Esquema SQL de empresas, almacenes, pedidos y traspasos con claves compuestas y las operaciones que la base de datos rechaza
Las claves compuestas convierten las reglas entre empresas en restricciones que nadie se puede saltar

Numeración de documentos por empresa

Cada sociedad factura con su propia numeración. El Reglamento de facturación, Real Decreto 1619/2012, exige en su artículo 6 que la numeración sea correlativa dentro de cada serie y permite series distintas, por ejemplo por establecimientos, y obliga a usar una serie propia para las facturas rectificativas. En el ERP eso se traduce en un contador por empresa y serie, que se incrementa dentro de la misma transacción que crea el documento para que dos usuarios no obtengan el mismo número ni quede un hueco.

Los pedidos y albaranes no tienen esa exigencia legal, pero conviene aplicar la misma regla: cada empresa con sus series, y una restricción única sobre empresa, serie y número. Si hoy cada sociedad lleva sus series en hojas de cálculo que hacen de registro de documentos, este es el momento de llevarlas al sistema.

Comparativa de datos compartidos por el grupo frente a datos propios de cada empresa: artículos, clientes, tarifas y series
Artículos y fichas se comparten; tarifas, series y almacenes pertenecen a cada sociedad

Permisos, consolidación y migración

Los permisos se asignan por empresa: un mismo usuario puede ser administrador en una sociedad y solo consultar en otra. El panel de administración con permisos por empresa es donde se gestionan esas asignaciones, y cada sesión fija las empresas permitidas antes de consultar. Los operarios que preparan pedidos en varias naves usan la misma lógica desde una app de almacén multiempresa en Madrid.

La consolidación sale de sumar por empresa y eliminar las operaciones internas del grupo, que en un modelo único se identifican porque el cliente o el proveedor es otra sociedad del grupo. Los informes financieros se construyen como en una aplicación web de gestión financiera a medida, sobre los mismos datos y sin exportaciones intermedias.

Si vienes de varias instalaciones, la migración es también una deduplicación: los artículos y clientes repetidos se fusionan antes de cargarlos en el maestro común, y cada empresa conserva su histórico. Es más trabajo que una migración simple, y conviene contemplarlo en el presupuesto de una aplicación web a medida desde el principio.

Checklist para un ERP multiempresa y multialmacén: maestros, company_id, políticas por fila, claves compuestas y series
Seis comprobaciones antes de unificar varias sociedades en un solo ERP

El Precio de Mantener un ERP por Empresa

Varias instalaciones parecen más sencillas al principio, pero cada artículo nuevo se da de alta varias veces, cada traspaso se registra en dos sistemas y cada cierre exige cuadrar a mano. Un modelo único con la empresa en cada registro y reglas en la base de datos elimina ese trabajo y reduce el riesgo de errores entre sociedades, y por eso es el planteamiento que defendemos como estudio de software a medida e integración de sistemas.

En Codezone diseñamos y desarrollamos ERP multiempresa y multialmacén, migramos los datos de cada sociedad y seguimos con el mantenimiento de un ERP multialmacén en Madrid. Si tu grupo trabaja hoy con un sistema por empresa, cuéntanos cuántas sociedades y almacenes gestionáis y te proponemos un modelo de datos concreto.