Volver a la arquitectura

Modelo de datos · documento oficial

Las tablas del negocio

Modelo vigente y canónico. Cualquier otra página que muestre tablas se subordina a esta.

Cómo se traduce la operación —importar, almacenar, vender y facturar— a tablas. El producto es el concepto comercial; la variante (con su código SKU) es lo que de verdad se compra, se vende y se cuenta en el almacén. El stock no se escribe a mano: se calcula sumando los movimientos (detalle en Cómo se deriva el stock).

Son 3 bases de datos Postgres separadas, no una: leon_principal (todo lo de este documento salvo lo indicado), leon_fotos (imágenes de producto) y leon_facturas (documento SUNAT firmado). No hay llaves foráneas entre ellas — el vínculo es lógico, por variante_id/sku o comprobante_id, resuelto en el código, no en la base.
entradas salidas cobro Catálogo producto · variante Precios por tipo de cliente Compras importación Inventario movimientos Ventas pedidos Facturación comprobantes · pagos

El catálogo alimenta todo (línea punteada). La compra suma stock, la venta lo resta y genera el cobro. El equipo es transversal y se omite aquí.

Catálogo

qué vendemos
productoEl concepto comercial. No tiene código SKU ni stock propio; es la "idea" del producto.
CampoEjemploDescripción
id
PK
1Número interno que el sistema asigna solo. Sirve para no confundir productos con el mismo nombre.
nombreAudífonos inalámbricosEl nombre del producto tal como lo conoce el cliente.
descripcionBluetooth 5.0, 20 h bateríaTexto que explica el producto en el catálogo.
marcaSonelyLa marca, si la tiene.
categoria_id
FK
4A qué categoría pertenece. Apunta a categoria.
activoSi se muestra o no en la tienda.
varianteEl código SKU real. Es lo que se compra, se vende y se cuenta en el almacén.
CampoEjemploDescripción
id
PK
12Número interno de esta versión exacta del producto.
producto_id
FK
1De qué producto es esta versión. Apunta a producto.
skuAUD-NEG-001Código único de esta versión. Es lo que se rotula y se cuenta físicamente.
codigo_barras7751234567890El código de barras para escanear, si lo trae.
atributosColor: negroLo que diferencia esta versión de otras del mismo producto (color, talla, medida).
activoSi esta versión sigue a la venta.
categoriaCómo se agrupan los productos en el catálogo.
CampoEjemploDescripción
id
PK
4Número interno de la categoría.
nombreAudioNombre visible de la categoría.
slugaudioEl nombre en formato de dirección web (sin tildes ni espacios).
padre_id
FK
2Si es una subcategoría, de cuál depende. Apunta a categoria.
imagen_productoLas fotos de una variante. Vive en leon_fotos (otra base): sin FK real a variante, el vínculo es por variante_id/sku.
CampoEjemploDescripción
id
PK
30Número interno de la imagen.
variante_id12De qué versión del producto es la foto. Referencia lógica a variante (bases distintas, sin FK).
skuAUD-NEG-001Copia del SKU, para no depender de un join entre bases al mostrarla.
orden1En qué posición aparece.
es_principalCalculada por Postgres (orden = 1), no se edita directamente.
altAudífonos, vista frontalTexto alternativo de la imagen.
imagen_renderEl archivo real de cada tamaño (miniatura/media/original). El binario se guarda en Postgres o, en modo CDN, solo la URL.
CampoEjemploDescripción
id
PK
61Número interno del render.
imagen_id
FK
30De qué imagen es este tamaño. Apunta a imagen_producto.
tamanomediaminiatura, media u original.
mime / ancho / alto / bytesimage/webp · 800×600Metadatos del archivo ya procesado (siempre WebP).
contenidobinarioEl archivo en sí, guardado en Postgres (modo autónomo, el que se usa hoy).
urlnullSolo se usa en modo CDN/S3 (no activo hoy); si está vacía, se sirve contenido.

Inventario

cuánto tenemos
almacenLas zonas físicas donde se almacena la mercadería.
CampoEjemploDescripción
id
PK
1Número interno de la zona.
nombreCasa — SalaNombre de la zona o estante.
tipoZonaSi es una zona, un estante, una caja, etc.
direccionAv. Primavera 123, LimaDónde queda físicamente.
movimiento_inventarioEl cuaderno de entradas y salidas. El stock disponible se calcula sumando esta tabla, nunca se escribe a mano.
CampoEjemploDescripción
id
PK
500Número interno del movimiento.
variante_id
FK
12Qué versión del producto se movió. Apunta a variante.
almacen_id
FK
1En qué zona ocurrió. Apunta a almacen.
tipoEntradaSi suma (entrada/compra), resta (salida/venta), corrige (ajuste/merma) o reserva. Una reserva aparta stock para un pedido a futuro: no altera el stock físico, solo baja el disponible para venta.
cantidad50Cuántas unidades entran o salen. En una reserva es una magnitud positiva (lo apartado).
reserva_estadoActivaSolo en movimientos de tipo reserva (vacío en el resto): activa (aparta stock), consumida (el pedido se pagó y pasó a venta) o liberada (expiró, se anuló o se reeditaron líneas). Solo las activas restan del disponible.
linea_pedido_id
FK
140Si el movimiento nace de una línea de pedido (reserva o venta), a cuál. Apunta a linea_pedido.
referenciaCompra #8De dónde viene el movimiento (una compra, una venta, un conteo, una reserva).
fecha15/06/2026Cuándo ocurrió.

Con reservas, el stock se lee en tres cifras: físico = suma de movimientos no-reserva; reservado = suma de reservas activas; disponible = físico − reservado. Solo se puede vender/reservar hasta el disponible.

Compras / Importación

Parte de importación
proveedorEl fabricante o mayorista que provee desde China. Equivale a la antigua tabla «Distribuidores».
CampoEjemploDescripción
id
PK
3Número interno del proveedor.
nombreShenzhen Sonely Co.Nombre de la fábrica o proveedor.
paisChinaDe dónde importamos.
contactoWeChat · ventas@…Cómo se les contacta.
monedaUSDEn qué moneda nos cobran.
condicionesMOQ 100 udsCantidad mínima de compra y otras condiciones acordadas.
orden_compraUn pedido que le hacemos a un proveedor.
CampoEjemploDescripción
id
PK
8Número interno del pedido de compra.
proveedor_id
FK
3A quién le compramos. Apunta a proveedor.
fecha01/05/2026Cuándo se hizo el pedido.
estadoEn tránsitoEn qué punto va (pedido, producción, en tránsito, recibido).
monedaUSDEn qué moneda se pactó.
tipo_cambio3.75Cuántos soles vale 1 dólar ese día. Se guarda para calcular el costo real en soles.
linea_orden_compraEl detalle del pedido: qué se compró y a qué precio en origen.
CampoEjemploDescripción
id
PK
20Número interno de la línea.
orden_compra_id
FK
8De qué pedido es. Apunta a orden_compra.
variante_id
FK
12Qué versión del producto. Apunta a variante.
cantidad200Cuántas unidades se pidieron.
precio_unitarioUSD 4.50Lo que cuesta cada unidad puesta en fábrica, antes de flete y aduanas.
embarqueEl viaje físico de la mercadería hasta Perú.
CampoEjemploDescripción
id
PK
5Número interno del embarque.
orden_compra_id
FK
8Qué pedido viaja. Apunta a orden_compra.
incotermFOBHasta qué punto del viaje paga el proveedor el transporte.
contenedorMSC · ABC123Naviera y número de contenedor.
fecha_salida01/05/2026Cuándo zarpó de origen.
fecha_llegada10/06/2026Cuándo llegó a puerto. Se guarda aparte para medir cuánto tardó el viaje.
documento_aduaneroLos papeles legales de la importación.
CampoEjemploDescripción
id
PK
9Número interno del documento.
embarque_id
FK
5De qué embarque es. Apunta a embarque.
tipoDUAQué documento es (DUA, factura comercial, packing list…).
numero118-2026-001234El número oficial del documento.
archivodua.pdfEl archivo escaneado.
costo_importacionFlete, aduana y seguro. Se reparten entre las unidades para saber cuánto costó de verdad cada producto.
CampoEjemploDescripción
id
PK
14Número interno del costo.
embarque_id
FK
5A qué embarque pertenece. Apunta a embarque.
tipoFleteSi es flete, aduana o seguro.
montoUSD 800Cuánto se pagó por ese concepto.
monedaUSDEn qué moneda se pagó.
muestraLas muestras para revisar calidad antes de importar en grande.
CampoEjemploDescripción
id
PK
2Número interno de la muestra.
proveedor_id
FK
3Quién la envió. Apunta a proveedor.
descripcionAudífonos v2Qué muestra es.
link_origen1688.com/…El enlace del producto en 1688/Alibaba de donde salió la muestra.
costoUSD 12Lo que costó la muestra más su envío.
estadoAprobadaSi pasó la revisión de calidad o no.
fecha10/04/2026Cuándo se recibió.

Ventas

pedidos y clientes
clienteQuién nos compra. El documento decide si recibe boleta o factura.
CampoEjemploDescripción
id
PK
40Número interno del cliente.
nombreLibrería San MarcosNombre de la persona o la empresa.
tipoEmpresaParticular o empresa.
doc_tipoRUCTipo de documento: DNI para personas, RUC para empresas.
doc_numero20512345678El número del documento. Es obligatorio para emitir el comprobante.
direccion_fiscalJr. Lampa 200, LimaEl domicilio que figura en el RUC. SUNAT lo exige en la factura.
email / telefonoventas@… · 999…Cómo se le contacta.
pedidoUna venta. Al confirmarse, descuenta el stock como salida. El total no es una columna: se calcula sumando sus líneas (igual que el stock).
CampoEjemploDescripción
id
PK
88Número interno del pedido.
cliente_id
FK
40Quién compra. Apunta a cliente.
canalWhatsAppPor dónde llegó la venta (WhatsApp, Instagram, presencial, correo, web).
fecha16/06/2026Cuándo se hizo el pedido.
estadoPagadoPendiente, pagado, enviado, entregado, anulado o expirado (reserva vencida sin pago).
es_reservaPedido a futuro: al crearse aparta el stock (reserva) en vez de dejarlo libre. Solo se puede editar mientras está pendiente.
fecha_expiracion23/06/2026 12:00Solo en pedidos a futuro: hasta cuándo se mantiene la reserva. Por defecto 7 días, máximo 7. Si no se paga antes, el sistema libera el stock y marca el pedido Expirado.
tipo_comprobanteFacturaComprobante declarado (Boleta, Factura o Ninguno). Por defecto según el documento del cliente (RUC→Factura, DNI→Boleta); Factura exige RUC. Es solo intención: no emite nada (la emisión es otra fase).
notasEntregar después de las 3pmInstrucciones especiales del cliente.
creado_en16/06/2026 10:32Cuándo se registró en el sistema.
linea_pedidoEl detalle de la venta: qué se llevó y a qué precio.
CampoEjemploDescripción
id
PK
120Número interno de la línea.
pedido_id
FK
88De qué pedido es. Apunta a pedido.
variante_id
FK
12Qué versión del producto se vendió. Apunta a variante.
cantidad3Cuántas unidades.
precio_unitarioS/ 60El precio al que se vendió en ese momento. Se guarda aunque el precio cambie después.
precio_lista_originalS/ 75El precio de lista de la variante cuando se creó la línea. Sirve para auditar el descuento si el empleado bajó el precio.
precio_modificadoMarca si el precio unitario se cambió a mano respecto al de lista (un descuento), no un precio arbitrario.
envio_clienteEl despacho del pedido y su seguimiento. courier/tracking son texto libre: no hay integración real con ninguna empresa de courier (ver Servicios externos).
CampoEjemploDescripción
id
PK
22Número interno del envío.
pedido_id
FK
88Qué pedido se envía. Apunta a pedido (uno a uno).
courierOlva CourierCon qué empresa se envía. Texto libre, escrito a mano.
trackingOLV-99812El código para rastrear el paquete, si lo hay. Texto libre, no se consulta ninguna API.
direccionAv. Larco 500, MirafloresLa dirección de entrega de este envío en concreto.
costo_envioS/ 15Lo que cuesta el despacho.
estadoEntregadoPreparando, en camino, entregado o anulado.
fecha_estimada / fecha_entrega18/06/2026Cuándo se prometió entregar y cuándo se entregó de verdad.

Precios

no es un solo número
lista_preciosUn mismo producto puede tener un precio para mayoristas y otro para el público.Fase posterior
CampoEjemploDescripción
id
PK
1Número interno de la lista.
nombreMayoristaNombre de la lista de precios.
tipo_clienteEmpresaA qué tipo de cliente se aplica.
precio_varianteEl precio de cada versión del producto dentro de cada lista.Fase posterior
CampoEjemploDescripción
id
PK
33Número interno.
variante_id
FK
12Qué versión del producto. Apunta a variante.
lista_precios_id
FK
1A qué lista pertenece. Apunta a lista_precios.
precioS/ 45El precio de venta.
monedaPENEn qué moneda (soles).

Facturación y pagos

documentos legales
comprobanteLa boleta o factura, con lo que se muestra en la intranet. El XML/CDR firmado no está aquí: vive en leon_facturas (ver factura_documento más abajo).
CampoEjemploDescripción
id
PK
60Número interno del comprobante.
pedido_id
FK
88De qué venta es. Apunta a pedido.
tipoBoletaFactura para empresas, boleta para personas.
serie / correlativoB001-000123El número oficial que exige SUNAT.
fecha_emision16/06/2026La fecha legal del comprobante. Puede diferir de la del pedido.
igv / totalS/ 68.64 · S/ 450El impuesto (18%) y el monto total con IGV incluido.
estado_sunatAceptadoPendiente, aceptado o rechazado — hoy siempre simulado (ver Servicios externos).
pagoCómo y cuánto pagó el cliente.
CampoEjemploDescripción
id
PK
70Número interno del pago.
pedido_id
FK
88Qué pedido se pagó. Apunta a pedido.
metodoYapeCómo pagó (Yape, Plin, tarjeta, PagoEfectivo…).
montoS/ 450Cuánto pagó.
estadoConfirmadoSi el pago se confirmó o no.
voucher_url/vouchers/yape-70.jpgLa captura del Yape/Plin que envía el cliente como prueba.
referencia / fechaOp. 00012 · 16/06El código de operación y cuándo se pagó.
nota_creditoCuando hay una devolución o anulación, SUNAT exige emitir una nota de crédito que referencia al comprobante original.
CampoEjemploDescripción
id
PK
12Número interno de la nota de crédito.
comprobante_id
FK
60Qué boleta o factura corrige. Apunta a comprobante.
motivoDevoluciónPor qué se emite (devolución, anulación, descuento, error).
serie / correlativoBC01-000045El número oficial de la nota que exige SUNAT.
montoS/ 150Cuánto se devuelve o descuenta.
estado_sunatAceptadoSi SUNAT la aceptó, la rechazó o está pendiente.

Equipo

quién opera
usuarioEl equipo interno, cada usuario con su rol. Sustituye a la antigua tabla «Personal / trabajadores».
CampoEjemploDescripción
id
PK
1Número interno del usuario.
nombreFranitza LeónNombre de la persona.
emailfranitza@…Con qué correo entra al sistema.
rolAbastecimientoQué puede hacer en el sistema (abastecimiento, ventas, marketing, sistemas, admin).
activoSi su acceso está habilitado. Se apaga sola al crear la cuenta hasta que se aprueba (ver aprobado).
aprobadoSi un admin ya revisó la cuenta. Las que crea un admin desde Equipo nacen aprobadas; las que llegan por autoregistro (/auth/registro) nacen en No y quedan bloqueadas hasta que un admin las aprueba.
temaclaroPreferencia de tema claro/oscuro de la intranet. Sigue a la persona entre dispositivos.
creado_en01/01/2026Cuándo se creó la cuenta.

Documentos SUNAT

base leon_facturas
factura_documentoEl comprobante electrónico completo. Vínculo lógico con comprobante por comprobante_id, sin FK real (otra base).
CampoEjemploDescripción
id
PK
60Número interno del documento.
comprobante_id60Referencia lógica a comprobante (leon_principal).
documentoJSONEl comprobante completo en JSON, estilo UBL simplificado.
xml_firmado / cdr_xmlstubHoy son un simulacro: no hay firma digital real ni CDR devuelto por SUNAT (ver Servicios externos).
estado_sunataceptadoSe marca "aceptado" automáticamente; no hay validación real.
factura_eventoLa bitácora de cada documento: generado → enviado → aceptado (o rechazado).
CampoEjemploDescripción
id
PK
200Número interno del evento.
factura_id
FK
60A qué documento pertenece. Apunta a factura_documento.
eventoaceptadogenerado, enviado, aceptado, rechazado o anulado.

Auditoría

quién hizo qué
registro_actividadUn registro por cada acción relevante. Solo lectura desde la intranet — ver Registro de actividad.
CampoEjemploDescripción
id
PK
900Número interno del registro.
usuario_id1Quién hizo la acción. Referencia a usuario sin FK forzada (se aplica antes de que exista auth_user).
accioncrearcrear, editar, eliminar, activar, desactivar, login o logout.
modelo_afectado / objeto_reprProducto · "Cuaderno A4"Qué tipo de dato y cuál en concreto.
descripcionAndrei ha creado el producto…La frase legible que se muestra en pantalla.
timestamp16/06/2026 10:32Cuándo ocurrió. Indexado para consultar rápido por fecha.
PK Llave primaria — el número que identifica cada fila FK Llave foránea — apunta a otra tabla Fase posterior Difiérelo hasta que el volumen lo justifique

Las listas de precios por tipo de cliente siguen marcadas "Fase posterior": todavía no existen, hoy el precio es el mismo para todos. Tres ideas sostienen el modelo: el código SKU vive en la variante, el stock se calcula sumando los movimientos (nunca es una columna), y son 3 bases separadas (principal, fotos, facturas) sin FK entre ellas.