Migración desde erp-retail/database - Estándar multi-repo v2
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
aaf5822f19
commit
f7c584278a
196
HERENCIA-ERP-CORE.md
Normal file
196
HERENCIA-ERP-CORE.md
Normal file
@ -0,0 +1,196 @@
|
||||
# Herencia de Base de Datos - ERP Core -> Retail
|
||||
|
||||
**Fecha:** 2025-12-08
|
||||
**Versión:** 1.0
|
||||
**Vertical:** Retail
|
||||
**Nivel:** 2B.2
|
||||
|
||||
---
|
||||
|
||||
## RESUMEN
|
||||
|
||||
La vertical de Retail hereda los schemas base del ERP Core y extiende con schemas específicos del dominio de punto de venta y comercio minorista.
|
||||
|
||||
**Ubicación DDL Core:** `apps/erp-core/database/ddl/`
|
||||
|
||||
---
|
||||
|
||||
## ARQUITECTURA DE HERENCIA
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ ERP CORE (Base) │
|
||||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||
│ │ auth │ │ core │ │financial│ │inventory│ │ purchase │ │
|
||||
│ │ 26 tbl │ │ 12 tbl │ │ 15 tbl │ │ 15 tbl │ │ 8 tbl │ │
|
||||
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
|
||||
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
|
||||
│ │ sales │ │analytics│ │ system │ │ crm │ │
|
||||
│ │ 6 tbl │ │ 5 tbl │ │ 10 tbl │ │ 5 tbl │ │
|
||||
│ └─────────┘ └─────────┘ └─────────┘ └─────────┘ │
|
||||
│ TOTAL: ~102 tablas heredadas │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
│
|
||||
│ HEREDA
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────────┐
|
||||
│ RETAIL (Extensiones) │
|
||||
│ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │
|
||||
│ │ pos │ │ stores │ │ pricing │ │
|
||||
│ │ (punto venta) │ │ (sucursales) │ │ (promociones) │ │
|
||||
│ └───────────────┘ └───────────────┘ └───────────────┘ │
|
||||
│ EXTENSIONES: ~30 tablas (planificadas) │
|
||||
└─────────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SCHEMAS HEREDADOS DEL CORE
|
||||
|
||||
| Schema | Tablas | Uso en Retail |
|
||||
|--------|--------|---------------|
|
||||
| `auth` | 26 | Autenticación, usuarios por sucursal |
|
||||
| `core` | 12 | Partners (clientes), catálogos |
|
||||
| `financial` | 15 | Facturas, cuentas, caja |
|
||||
| `inventory` | 15 | Inventario multi-sucursal |
|
||||
| `purchase` | 8 | Compras a proveedores |
|
||||
| `sales` | 6 | Ventas base |
|
||||
| `crm` | 5 | Clientes frecuentes |
|
||||
| `analytics` | 5 | Métricas de venta |
|
||||
| `system` | 10 | Notificaciones |
|
||||
|
||||
**Total heredado:** ~102 tablas
|
||||
|
||||
---
|
||||
|
||||
## SCHEMAS ESPECÍFICOS DE RETAIL (Planificados)
|
||||
|
||||
### 1. Schema `pos` (estimado 12+ tablas)
|
||||
|
||||
**Propósito:** Punto de venta y operaciones de caja
|
||||
|
||||
```sql
|
||||
-- Tablas principales planificadas:
|
||||
pos.cash_registers -- Cajas registradoras
|
||||
pos.cash_sessions -- Sesiones de caja
|
||||
pos.pos_orders -- Tickets/ventas POS
|
||||
pos.pos_order_lines -- Líneas de ticket
|
||||
pos.payment_methods -- Métodos de pago
|
||||
pos.cash_movements -- Movimientos de caja
|
||||
pos.cash_counts -- Cortes de caja
|
||||
pos.receipts -- Recibos
|
||||
```
|
||||
|
||||
### 2. Schema `stores` (estimado 8+ tablas)
|
||||
|
||||
**Propósito:** Gestión de sucursales
|
||||
|
||||
```sql
|
||||
-- Tablas principales planificadas:
|
||||
stores.branches -- Sucursales
|
||||
stores.branch_inventory -- Inventario por sucursal
|
||||
stores.transfers -- Transferencias entre sucursales
|
||||
stores.transfer_lines -- Líneas de transferencia
|
||||
stores.branch_employees -- Empleados por sucursal
|
||||
```
|
||||
|
||||
### 3. Schema `pricing` (estimado 10+ tablas)
|
||||
|
||||
**Propósito:** Precios y promociones
|
||||
|
||||
```sql
|
||||
-- Extiende: sales schema del core
|
||||
pricing.price_lists -- Listas de precios
|
||||
pricing.promotions -- Promociones
|
||||
pricing.discounts -- Descuentos
|
||||
pricing.loyalty_programs -- Programas de lealtad
|
||||
pricing.coupons -- Cupones
|
||||
pricing.price_history -- Historial de precios
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SPECS DEL CORE APLICABLES
|
||||
|
||||
**Documento detallado:** `orchestration/00-guidelines/HERENCIA-SPECS-CORE.md`
|
||||
|
||||
### Correcciones de DDL Core (2025-12-08)
|
||||
|
||||
El DDL del ERP-Core fue corregido para resolver FK inválidas:
|
||||
|
||||
1. **stock_valuation_layers**: Campos `journal_entry_id` y `journal_entry_line_id` (antes `account_move_*`)
|
||||
2. **stock_move_consume_rel**: Nueva tabla de trazabilidad (antes `move_line_consume_rel`)
|
||||
3. **category_stock_accounts**: FK corregida a `core.product_categories`
|
||||
4. **product_categories**: ALTERs ahora apuntan a schema `core`
|
||||
|
||||
### SPECS Obligatorias
|
||||
|
||||
| Spec Core | Aplicación en Retail | SP | Estado |
|
||||
|-----------|---------------------|----:|--------|
|
||||
| SPEC-SISTEMA-SECUENCIAS | Foliado de tickets y facturas | 8 | ✅ DDL LISTO |
|
||||
| SPEC-VALORACION-INVENTARIO | Costeo de mercancía | 21 | ✅ DDL LISTO |
|
||||
| SPEC-SEGURIDAD-API-KEYS-PERMISOS | Control de acceso por sucursal | 31 | ✅ DDL LISTO |
|
||||
| SPEC-PRICING-RULES | Precios y promociones | 8 | PENDIENTE |
|
||||
| SPEC-INVENTARIOS-CICLICOS | Conteos en sucursales | 13 | ✅ DDL LISTO |
|
||||
| SPEC-TRAZABILIDAD-LOTES-SERIES | Productos con lote/serie | 13 | ✅ DDL LISTO |
|
||||
| SPEC-MAIL-THREAD-TRACKING | Comunicación con clientes | 13 | PENDIENTE |
|
||||
| SPEC-WIZARD-TRANSIENT-MODEL | Wizards de cierre de caja | 8 | PENDIENTE |
|
||||
|
||||
### SPECS Opcionales
|
||||
|
||||
| Spec Core | Decisión | Razón |
|
||||
|-----------|----------|-------|
|
||||
| SPEC-PORTAL-PROVEEDORES | EVALUAR | Para compras centralizadas |
|
||||
| SPEC-TAREAS-RECURRENTES | EVALUAR | Para reorden automático |
|
||||
|
||||
### SPECS No Aplican
|
||||
|
||||
| Spec Core | Razón |
|
||||
|-----------|-------|
|
||||
| SPEC-INTEGRACION-CALENDAR | No requiere calendario de citas |
|
||||
| SPEC-PROYECTOS-DEPENDENCIAS-BURNDOWN | No hay proyectos largos |
|
||||
| SPEC-FIRMA-ELECTRONICA-NOM151 | No aplica para tickets POS |
|
||||
|
||||
---
|
||||
|
||||
## ORDEN DE EJECUCIÓN DDL (Futuro)
|
||||
|
||||
```bash
|
||||
# PASO 1: Cargar ERP Core (base)
|
||||
cd apps/erp-core/database
|
||||
./scripts/reset-database.sh --force
|
||||
|
||||
# PASO 2: Cargar extensiones de Retail
|
||||
cd apps/verticales/retail/database
|
||||
psql $DATABASE_URL -f init/00-extensions.sql
|
||||
psql $DATABASE_URL -f init/01-create-schemas.sql
|
||||
psql $DATABASE_URL -f init/02-pos-tables.sql
|
||||
psql $DATABASE_URL -f init/03-stores-tables.sql
|
||||
psql $DATABASE_URL -f init/04-pricing-tables.sql
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## MAPEO DE NOMENCLATURA
|
||||
|
||||
| Core | Retail |
|
||||
|------|--------|
|
||||
| `core.partners` | Clientes, proveedores |
|
||||
| `inventory.products` | Productos de venta |
|
||||
| `inventory.locations` | Almacenes de sucursal |
|
||||
| `sales.sale_orders` | Base para POS orders |
|
||||
| `financial.invoices` | Facturas de venta |
|
||||
|
||||
---
|
||||
|
||||
## REFERENCIAS
|
||||
|
||||
- ERP Core DDL: `apps/erp-core/database/ddl/`
|
||||
- ERP Core README: `apps/erp-core/database/README.md`
|
||||
- Directivas: `orchestration/directivas/`
|
||||
- Inventarios: `orchestration/inventarios/`
|
||||
|
||||
---
|
||||
|
||||
**Documento de herencia oficial**
|
||||
**Última actualización:** 2025-12-08
|
||||
84
README.md
84
README.md
@ -1,3 +1,83 @@
|
||||
# erp-retail-database-v2
|
||||
# Base de Datos - ERP Retail/POS
|
||||
|
||||
Database de erp-retail - Workspace V2
|
||||
## Resumen
|
||||
|
||||
| Aspecto | Valor |
|
||||
|---------|-------|
|
||||
| **Schema principal** | `retail` |
|
||||
| **Tablas específicas** | 16 |
|
||||
| **ENUMs** | 6 |
|
||||
| **Hereda de ERP-Core** | 144 tablas (12 schemas) |
|
||||
|
||||
## Prerequisitos
|
||||
|
||||
1. **ERP-Core instalado** con todos sus schemas
|
||||
2. **Extensiones PostgreSQL**: pg_trgm
|
||||
|
||||
## Orden de Ejecución DDL
|
||||
|
||||
```bash
|
||||
# 1. Instalar ERP-Core primero
|
||||
cd apps/erp-core/database
|
||||
./scripts/reset-database.sh
|
||||
|
||||
# 2. Instalar extensión Retail
|
||||
cd apps/verticales/retail/database
|
||||
psql $DATABASE_URL -f init/00-extensions.sql
|
||||
psql $DATABASE_URL -f init/01-create-schemas.sql
|
||||
psql $DATABASE_URL -f init/02-rls-functions.sql
|
||||
psql $DATABASE_URL -f init/03-retail-tables.sql
|
||||
```
|
||||
|
||||
## Tablas Implementadas
|
||||
|
||||
### Schema: retail (16 tablas)
|
||||
|
||||
| Tabla | Módulo | Descripción |
|
||||
|-------|--------|-------------|
|
||||
| branches | RT-002 | Sucursales |
|
||||
| cash_registers | RT-001 | Cajas registradoras |
|
||||
| pos_sessions | RT-001 | Sesiones de POS |
|
||||
| pos_orders | RT-001 | Ventas/Órdenes |
|
||||
| pos_order_lines | RT-001 | Líneas de venta |
|
||||
| pos_payments | RT-001 | Pagos (mixtos) |
|
||||
| cash_movements | RT-001 | Entradas/salidas efectivo |
|
||||
| branch_stock | RT-002 | Stock por sucursal |
|
||||
| stock_transfers | RT-002 | Transferencias |
|
||||
| stock_transfer_lines | RT-002 | Líneas de transferencia |
|
||||
| product_barcodes | RT-003 | Códigos de barras |
|
||||
| promotions | RT-003 | Promociones |
|
||||
| promotion_products | RT-003 | Productos en promo |
|
||||
| loyalty_programs | RT-004 | Programas fidelización |
|
||||
| loyalty_cards | RT-004 | Tarjetas |
|
||||
| loyalty_transactions | RT-004 | Transacciones puntos |
|
||||
|
||||
## ENUMs
|
||||
|
||||
| Enum | Valores |
|
||||
|------|---------|
|
||||
| pos_session_status | opening, open, closing, closed |
|
||||
| pos_order_status | draft, paid, done, cancelled, refunded |
|
||||
| payment_method | cash, card, transfer, credit, mixed |
|
||||
| cash_movement_type | in, out |
|
||||
| transfer_status | draft, pending, in_transit, received, cancelled |
|
||||
| promotion_type | percentage, fixed_amount, buy_x_get_y, bundle |
|
||||
|
||||
## Row Level Security
|
||||
|
||||
Todas las tablas tienen RLS con:
|
||||
```sql
|
||||
tenant_id = current_setting('app.current_tenant_id', true)::UUID
|
||||
```
|
||||
|
||||
## Consideraciones Especiales
|
||||
|
||||
- **Operación offline**: POS puede operar sin conexión
|
||||
- **Rendimiento**: <100ms por transacción
|
||||
- **Hardware**: Integración con impresoras y lectores
|
||||
- **CFDI 4.0**: Facturación en tiempo real
|
||||
|
||||
## Referencias
|
||||
|
||||
- [HERENCIA-ERP-CORE.md](./HERENCIA-ERP-CORE.md)
|
||||
- [DATABASE_INVENTORY.yml](../orchestration/inventarios/DATABASE_INVENTORY.yml)
|
||||
|
||||
22
init/00-extensions.sql
Normal file
22
init/00-extensions.sql
Normal file
@ -0,0 +1,22 @@
|
||||
-- ============================================================================
|
||||
-- EXTENSIONES PostgreSQL - ERP Retail/POS
|
||||
-- ============================================================================
|
||||
-- Versión: 1.0.0
|
||||
-- Fecha: 2025-12-09
|
||||
-- Prerequisito: ERP-Core debe estar instalado
|
||||
-- ============================================================================
|
||||
|
||||
-- Verificar que ERP-Core esté instalado
|
||||
DO $$
|
||||
BEGIN
|
||||
IF NOT EXISTS (SELECT 1 FROM pg_namespace WHERE nspname = 'auth') THEN
|
||||
RAISE EXCEPTION 'ERP-Core no instalado. Ejecutar primero DDL de erp-core.';
|
||||
END IF;
|
||||
END $$;
|
||||
|
||||
-- Extensión para búsqueda de texto (productos, códigos)
|
||||
CREATE EXTENSION IF NOT EXISTS pg_trgm;
|
||||
|
||||
-- ============================================================================
|
||||
-- FIN EXTENSIONES
|
||||
-- ============================================================================
|
||||
15
init/01-create-schemas.sql
Normal file
15
init/01-create-schemas.sql
Normal file
@ -0,0 +1,15 @@
|
||||
-- ============================================================================
|
||||
-- SCHEMAS - ERP Retail/POS
|
||||
-- ============================================================================
|
||||
-- Versión: 1.0.0
|
||||
-- Fecha: 2025-12-09
|
||||
-- ============================================================================
|
||||
|
||||
-- Schema principal para operaciones de punto de venta
|
||||
CREATE SCHEMA IF NOT EXISTS retail;
|
||||
|
||||
COMMENT ON SCHEMA retail IS 'Schema para operaciones de punto de venta y retail';
|
||||
|
||||
-- ============================================================================
|
||||
-- FIN SCHEMAS
|
||||
-- ============================================================================
|
||||
30
init/02-rls-functions.sql
Normal file
30
init/02-rls-functions.sql
Normal file
@ -0,0 +1,30 @@
|
||||
-- ============================================================================
|
||||
-- FUNCIONES RLS - ERP Retail/POS
|
||||
-- ============================================================================
|
||||
-- Versión: 1.0.0
|
||||
-- Fecha: 2025-12-09
|
||||
-- Nota: Usa las funciones de contexto de ERP-Core (auth schema)
|
||||
-- ============================================================================
|
||||
|
||||
-- Las funciones principales están en ERP-Core:
|
||||
-- auth.get_current_tenant_id()
|
||||
-- auth.get_current_user_id()
|
||||
-- auth.get_current_company_id()
|
||||
|
||||
-- Función para obtener sucursal actual del usuario (para POS)
|
||||
CREATE OR REPLACE FUNCTION retail.get_current_branch_id()
|
||||
RETURNS UUID AS $$
|
||||
BEGIN
|
||||
RETURN current_setting('app.current_branch_id', true)::UUID;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
RETURN NULL;
|
||||
END;
|
||||
$$ LANGUAGE plpgsql STABLE;
|
||||
|
||||
COMMENT ON FUNCTION retail.get_current_branch_id IS
|
||||
'Obtiene el ID de la sucursal actual para operaciones POS';
|
||||
|
||||
-- ============================================================================
|
||||
-- FIN FUNCIONES RLS
|
||||
-- ============================================================================
|
||||
723
init/03-retail-tables.sql
Normal file
723
init/03-retail-tables.sql
Normal file
@ -0,0 +1,723 @@
|
||||
-- ============================================================================
|
||||
-- TABLAS RETAIL/POS - ERP Retail
|
||||
-- ============================================================================
|
||||
-- Módulos: RT-001 (POS), RT-002 (Inventario), RT-003 (Productos), RT-004 (Clientes)
|
||||
-- Versión: 1.0.0
|
||||
-- Fecha: 2025-12-09
|
||||
-- ============================================================================
|
||||
-- PREREQUISITOS:
|
||||
-- 1. ERP-Core instalado (auth, core, inventory, sales, financial)
|
||||
-- 2. Schema retail creado
|
||||
-- ============================================================================
|
||||
|
||||
-- ============================================================================
|
||||
-- TYPES (ENUMs)
|
||||
-- ============================================================================
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE retail.pos_session_status AS ENUM (
|
||||
'opening', 'open', 'closing', 'closed'
|
||||
);
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE retail.pos_order_status AS ENUM (
|
||||
'draft', 'paid', 'done', 'cancelled', 'refunded'
|
||||
);
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE retail.payment_method AS ENUM (
|
||||
'cash', 'card', 'transfer', 'credit', 'mixed'
|
||||
);
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE retail.cash_movement_type AS ENUM (
|
||||
'in', 'out'
|
||||
);
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE retail.transfer_status AS ENUM (
|
||||
'draft', 'pending', 'in_transit', 'received', 'cancelled'
|
||||
);
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
CREATE TYPE retail.promotion_type AS ENUM (
|
||||
'percentage', 'fixed_amount', 'buy_x_get_y', 'bundle'
|
||||
);
|
||||
EXCEPTION WHEN duplicate_object THEN NULL; END $$;
|
||||
|
||||
-- ============================================================================
|
||||
-- SUCURSALES Y CONFIGURACIÓN
|
||||
-- ============================================================================
|
||||
|
||||
-- Tabla: branches (Sucursales)
|
||||
CREATE TABLE IF NOT EXISTS retail.branches (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
||||
company_id UUID REFERENCES auth.companies(id),
|
||||
|
||||
-- Identificación
|
||||
code VARCHAR(20) NOT NULL,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
|
||||
-- Ubicación
|
||||
address VARCHAR(255),
|
||||
city VARCHAR(100),
|
||||
state VARCHAR(100),
|
||||
zip_code VARCHAR(10),
|
||||
country VARCHAR(100) DEFAULT 'México',
|
||||
latitude DECIMAL(10,8),
|
||||
longitude DECIMAL(11,8),
|
||||
|
||||
-- Contacto
|
||||
phone VARCHAR(20),
|
||||
email VARCHAR(255),
|
||||
manager_id UUID REFERENCES auth.users(id),
|
||||
|
||||
-- Configuración
|
||||
warehouse_id UUID, -- FK a inventory.warehouses (ERP Core)
|
||||
default_pricelist_id UUID,
|
||||
timezone VARCHAR(50) DEFAULT 'America/Mexico_City',
|
||||
|
||||
-- Control
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
opening_date DATE,
|
||||
|
||||
-- Auditoría
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES auth.users(id),
|
||||
updated_at TIMESTAMPTZ,
|
||||
updated_by UUID REFERENCES auth.users(id),
|
||||
deleted_at TIMESTAMPTZ,
|
||||
deleted_by UUID REFERENCES auth.users(id),
|
||||
|
||||
CONSTRAINT uq_branches_code UNIQUE (tenant_id, code)
|
||||
);
|
||||
|
||||
-- Tabla: cash_registers (Cajas registradoras)
|
||||
CREATE TABLE IF NOT EXISTS retail.cash_registers (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
||||
branch_id UUID NOT NULL REFERENCES retail.branches(id),
|
||||
|
||||
-- Identificación
|
||||
code VARCHAR(20) NOT NULL,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
|
||||
-- Configuración
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
default_payment_method retail.payment_method DEFAULT 'cash',
|
||||
|
||||
-- Auditoría
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES auth.users(id),
|
||||
updated_at TIMESTAMPTZ,
|
||||
updated_by UUID REFERENCES auth.users(id),
|
||||
|
||||
CONSTRAINT uq_cash_registers_code UNIQUE (tenant_id, branch_id, code)
|
||||
);
|
||||
|
||||
-- ============================================================================
|
||||
-- PUNTO DE VENTA (RT-001)
|
||||
-- ============================================================================
|
||||
|
||||
-- Tabla: pos_sessions (Sesiones de POS)
|
||||
CREATE TABLE IF NOT EXISTS retail.pos_sessions (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
||||
branch_id UUID NOT NULL REFERENCES retail.branches(id),
|
||||
cash_register_id UUID NOT NULL REFERENCES retail.cash_registers(id),
|
||||
|
||||
-- Usuario
|
||||
user_id UUID NOT NULL REFERENCES auth.users(id),
|
||||
|
||||
-- Estado
|
||||
status retail.pos_session_status NOT NULL DEFAULT 'opening',
|
||||
|
||||
-- Apertura
|
||||
opening_date TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
opening_balance DECIMAL(14,2) NOT NULL DEFAULT 0,
|
||||
|
||||
-- Cierre
|
||||
closing_date TIMESTAMPTZ,
|
||||
closing_balance DECIMAL(14,2),
|
||||
closing_notes TEXT,
|
||||
|
||||
-- Totales calculados
|
||||
total_sales DECIMAL(14,2) DEFAULT 0,
|
||||
total_refunds DECIMAL(14,2) DEFAULT 0,
|
||||
total_cash_in DECIMAL(14,2) DEFAULT 0,
|
||||
total_cash_out DECIMAL(14,2) DEFAULT 0,
|
||||
total_card DECIMAL(14,2) DEFAULT 0,
|
||||
total_transfer DECIMAL(14,2) DEFAULT 0,
|
||||
|
||||
-- Diferencia
|
||||
expected_balance DECIMAL(14,2),
|
||||
difference DECIMAL(14,2),
|
||||
|
||||
-- Auditoría
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES auth.users(id),
|
||||
updated_at TIMESTAMPTZ,
|
||||
updated_by UUID REFERENCES auth.users(id)
|
||||
);
|
||||
|
||||
-- Tabla: pos_orders (Órdenes/Ventas de POS)
|
||||
CREATE TABLE IF NOT EXISTS retail.pos_orders (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
||||
session_id UUID NOT NULL REFERENCES retail.pos_sessions(id),
|
||||
branch_id UUID NOT NULL REFERENCES retail.branches(id),
|
||||
|
||||
-- Número de ticket
|
||||
order_number VARCHAR(30) NOT NULL,
|
||||
order_date TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
|
||||
-- Cliente (opcional)
|
||||
customer_id UUID, -- FK a core.partners (ERP Core)
|
||||
customer_name VARCHAR(200),
|
||||
|
||||
-- Estado
|
||||
status retail.pos_order_status NOT NULL DEFAULT 'draft',
|
||||
|
||||
-- Totales
|
||||
subtotal DECIMAL(14,2) NOT NULL DEFAULT 0,
|
||||
discount_amount DECIMAL(14,2) DEFAULT 0,
|
||||
tax_amount DECIMAL(14,2) DEFAULT 0,
|
||||
total DECIMAL(14,2) NOT NULL DEFAULT 0,
|
||||
|
||||
-- Pago
|
||||
payment_method retail.payment_method,
|
||||
amount_paid DECIMAL(14,2) DEFAULT 0,
|
||||
change_amount DECIMAL(14,2) DEFAULT 0,
|
||||
|
||||
-- Facturación
|
||||
requires_invoice BOOLEAN DEFAULT FALSE,
|
||||
invoice_id UUID, -- FK a financial.invoices (ERP Core)
|
||||
|
||||
-- Notas
|
||||
notes TEXT,
|
||||
|
||||
-- Auditoría
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES auth.users(id),
|
||||
updated_at TIMESTAMPTZ,
|
||||
updated_by UUID REFERENCES auth.users(id),
|
||||
|
||||
CONSTRAINT uq_pos_orders_number UNIQUE (tenant_id, order_number)
|
||||
);
|
||||
|
||||
-- Tabla: pos_order_lines (Líneas de venta)
|
||||
CREATE TABLE IF NOT EXISTS retail.pos_order_lines (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
||||
order_id UUID NOT NULL REFERENCES retail.pos_orders(id) ON DELETE CASCADE,
|
||||
|
||||
-- Producto
|
||||
product_id UUID NOT NULL, -- FK a inventory.products (ERP Core)
|
||||
product_name VARCHAR(255) NOT NULL,
|
||||
barcode VARCHAR(50),
|
||||
|
||||
-- Cantidades
|
||||
quantity DECIMAL(12,4) NOT NULL,
|
||||
unit_price DECIMAL(12,4) NOT NULL,
|
||||
|
||||
-- Descuentos
|
||||
discount_percent DECIMAL(5,2) DEFAULT 0,
|
||||
discount_amount DECIMAL(12,2) DEFAULT 0,
|
||||
|
||||
-- Totales
|
||||
subtotal DECIMAL(14,2) GENERATED ALWAYS AS (quantity * unit_price) STORED,
|
||||
tax_amount DECIMAL(12,2) DEFAULT 0,
|
||||
total DECIMAL(14,2) NOT NULL,
|
||||
|
||||
-- Orden
|
||||
sequence INTEGER DEFAULT 1,
|
||||
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES auth.users(id)
|
||||
);
|
||||
|
||||
-- Tabla: pos_payments (Pagos de orden - para pagos mixtos)
|
||||
CREATE TABLE IF NOT EXISTS retail.pos_payments (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
||||
order_id UUID NOT NULL REFERENCES retail.pos_orders(id) ON DELETE CASCADE,
|
||||
|
||||
payment_method retail.payment_method NOT NULL,
|
||||
amount DECIMAL(14,2) NOT NULL,
|
||||
|
||||
-- Referencia (para tarjeta/transferencia)
|
||||
reference VARCHAR(100),
|
||||
card_last_four VARCHAR(4),
|
||||
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES auth.users(id)
|
||||
);
|
||||
|
||||
-- Tabla: cash_movements (Movimientos de efectivo)
|
||||
CREATE TABLE IF NOT EXISTS retail.cash_movements (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
||||
session_id UUID NOT NULL REFERENCES retail.pos_sessions(id),
|
||||
|
||||
-- Tipo y monto
|
||||
movement_type retail.cash_movement_type NOT NULL,
|
||||
amount DECIMAL(14,2) NOT NULL,
|
||||
|
||||
-- Razón
|
||||
reason VARCHAR(255) NOT NULL,
|
||||
notes TEXT,
|
||||
|
||||
-- Autorización
|
||||
authorized_by UUID REFERENCES auth.users(id),
|
||||
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES auth.users(id)
|
||||
);
|
||||
|
||||
-- ============================================================================
|
||||
-- INVENTARIO MULTI-SUCURSAL (RT-002)
|
||||
-- ============================================================================
|
||||
|
||||
-- Tabla: branch_stock (Stock por sucursal)
|
||||
CREATE TABLE IF NOT EXISTS retail.branch_stock (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
||||
branch_id UUID NOT NULL REFERENCES retail.branches(id),
|
||||
product_id UUID NOT NULL, -- FK a inventory.products (ERP Core)
|
||||
|
||||
-- Cantidades
|
||||
quantity_on_hand DECIMAL(12,4) NOT NULL DEFAULT 0,
|
||||
quantity_reserved DECIMAL(12,4) DEFAULT 0,
|
||||
quantity_available DECIMAL(12,4) GENERATED ALWAYS AS (quantity_on_hand - COALESCE(quantity_reserved, 0)) STORED,
|
||||
|
||||
-- Límites
|
||||
reorder_point DECIMAL(12,4),
|
||||
max_stock DECIMAL(12,4),
|
||||
|
||||
-- Control
|
||||
last_count_date DATE,
|
||||
last_count_qty DECIMAL(12,4),
|
||||
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
updated_at TIMESTAMPTZ,
|
||||
|
||||
CONSTRAINT uq_branch_stock UNIQUE (branch_id, product_id)
|
||||
);
|
||||
|
||||
-- Tabla: stock_transfers (Transferencias entre sucursales)
|
||||
CREATE TABLE IF NOT EXISTS retail.stock_transfers (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
||||
|
||||
-- Número
|
||||
transfer_number VARCHAR(30) NOT NULL,
|
||||
|
||||
-- Origen y destino
|
||||
source_branch_id UUID NOT NULL REFERENCES retail.branches(id),
|
||||
destination_branch_id UUID NOT NULL REFERENCES retail.branches(id),
|
||||
|
||||
-- Estado
|
||||
status retail.transfer_status NOT NULL DEFAULT 'draft',
|
||||
|
||||
-- Fechas
|
||||
request_date TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
ship_date TIMESTAMPTZ,
|
||||
receive_date TIMESTAMPTZ,
|
||||
|
||||
-- Responsables
|
||||
requested_by UUID NOT NULL REFERENCES auth.users(id),
|
||||
shipped_by UUID REFERENCES auth.users(id),
|
||||
received_by UUID REFERENCES auth.users(id),
|
||||
|
||||
-- Notas
|
||||
notes TEXT,
|
||||
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES auth.users(id),
|
||||
updated_at TIMESTAMPTZ,
|
||||
updated_by UUID REFERENCES auth.users(id),
|
||||
|
||||
CONSTRAINT uq_stock_transfers_number UNIQUE (tenant_id, transfer_number),
|
||||
CONSTRAINT chk_different_branches CHECK (source_branch_id != destination_branch_id)
|
||||
);
|
||||
|
||||
-- Tabla: stock_transfer_lines (Líneas de transferencia)
|
||||
CREATE TABLE IF NOT EXISTS retail.stock_transfer_lines (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
||||
transfer_id UUID NOT NULL REFERENCES retail.stock_transfers(id) ON DELETE CASCADE,
|
||||
|
||||
product_id UUID NOT NULL, -- FK a inventory.products (ERP Core)
|
||||
quantity_requested DECIMAL(12,4) NOT NULL,
|
||||
quantity_shipped DECIMAL(12,4),
|
||||
quantity_received DECIMAL(12,4),
|
||||
|
||||
notes TEXT,
|
||||
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES auth.users(id)
|
||||
);
|
||||
|
||||
-- ============================================================================
|
||||
-- PRODUCTOS RETAIL (RT-003)
|
||||
-- ============================================================================
|
||||
|
||||
-- Tabla: product_barcodes (Códigos de barras múltiples)
|
||||
CREATE TABLE IF NOT EXISTS retail.product_barcodes (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
||||
product_id UUID NOT NULL, -- FK a inventory.products (ERP Core)
|
||||
|
||||
barcode VARCHAR(50) NOT NULL,
|
||||
barcode_type VARCHAR(20) DEFAULT 'EAN13', -- EAN13, EAN8, UPC, CODE128, etc.
|
||||
is_primary BOOLEAN DEFAULT FALSE,
|
||||
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES auth.users(id),
|
||||
|
||||
CONSTRAINT uq_product_barcodes UNIQUE (tenant_id, barcode)
|
||||
);
|
||||
|
||||
-- Tabla: promotions (Promociones)
|
||||
CREATE TABLE IF NOT EXISTS retail.promotions (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
||||
|
||||
code VARCHAR(30) NOT NULL,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
|
||||
-- Tipo de promoción
|
||||
promotion_type retail.promotion_type NOT NULL,
|
||||
discount_value DECIMAL(10,2), -- Porcentaje o monto fijo
|
||||
|
||||
-- Vigencia
|
||||
start_date TIMESTAMPTZ NOT NULL,
|
||||
end_date TIMESTAMPTZ NOT NULL,
|
||||
|
||||
-- Aplicación
|
||||
applies_to_all BOOLEAN DEFAULT FALSE,
|
||||
min_quantity DECIMAL(12,4),
|
||||
min_amount DECIMAL(14,2),
|
||||
|
||||
-- Sucursales (NULL = todas)
|
||||
branch_ids UUID[],
|
||||
|
||||
-- Control
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
max_uses INTEGER,
|
||||
current_uses INTEGER DEFAULT 0,
|
||||
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES auth.users(id),
|
||||
updated_at TIMESTAMPTZ,
|
||||
updated_by UUID REFERENCES auth.users(id),
|
||||
|
||||
CONSTRAINT uq_promotions_code UNIQUE (tenant_id, code),
|
||||
CONSTRAINT chk_promotion_dates CHECK (end_date > start_date)
|
||||
);
|
||||
|
||||
-- Tabla: promotion_products (Productos en promoción)
|
||||
CREATE TABLE IF NOT EXISTS retail.promotion_products (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
||||
promotion_id UUID NOT NULL REFERENCES retail.promotions(id) ON DELETE CASCADE,
|
||||
product_id UUID NOT NULL, -- FK a inventory.products (ERP Core)
|
||||
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
|
||||
);
|
||||
|
||||
-- ============================================================================
|
||||
-- CLIENTES Y FIDELIZACIÓN (RT-004)
|
||||
-- ============================================================================
|
||||
|
||||
-- Tabla: loyalty_programs (Programas de fidelización)
|
||||
CREATE TABLE IF NOT EXISTS retail.loyalty_programs (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
||||
|
||||
code VARCHAR(20) NOT NULL,
|
||||
name VARCHAR(100) NOT NULL,
|
||||
description TEXT,
|
||||
|
||||
-- Configuración de puntos
|
||||
points_per_currency DECIMAL(10,4) DEFAULT 1, -- Puntos por peso gastado
|
||||
currency_per_point DECIMAL(10,4) DEFAULT 0.01, -- Valor del punto en pesos
|
||||
min_points_redeem INTEGER DEFAULT 100,
|
||||
|
||||
-- Vigencia
|
||||
points_expiry_days INTEGER, -- NULL = no expiran
|
||||
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES auth.users(id),
|
||||
updated_at TIMESTAMPTZ,
|
||||
updated_by UUID REFERENCES auth.users(id),
|
||||
|
||||
CONSTRAINT uq_loyalty_programs_code UNIQUE (tenant_id, code)
|
||||
);
|
||||
|
||||
-- Tabla: loyalty_cards (Tarjetas de fidelización)
|
||||
CREATE TABLE IF NOT EXISTS retail.loyalty_cards (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
||||
program_id UUID NOT NULL REFERENCES retail.loyalty_programs(id),
|
||||
customer_id UUID NOT NULL, -- FK a core.partners (ERP Core)
|
||||
|
||||
card_number VARCHAR(30) NOT NULL,
|
||||
issue_date DATE NOT NULL DEFAULT CURRENT_DATE,
|
||||
|
||||
-- Balance
|
||||
points_balance INTEGER NOT NULL DEFAULT 0,
|
||||
points_earned INTEGER NOT NULL DEFAULT 0,
|
||||
points_redeemed INTEGER NOT NULL DEFAULT 0,
|
||||
points_expired INTEGER NOT NULL DEFAULT 0,
|
||||
|
||||
is_active BOOLEAN NOT NULL DEFAULT TRUE,
|
||||
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES auth.users(id),
|
||||
updated_at TIMESTAMPTZ,
|
||||
updated_by UUID REFERENCES auth.users(id),
|
||||
|
||||
CONSTRAINT uq_loyalty_cards_number UNIQUE (tenant_id, card_number)
|
||||
);
|
||||
|
||||
-- Tabla: loyalty_transactions (Transacciones de puntos)
|
||||
CREATE TABLE IF NOT EXISTS retail.loyalty_transactions (
|
||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
||||
tenant_id UUID NOT NULL REFERENCES auth.tenants(id) ON DELETE CASCADE,
|
||||
card_id UUID NOT NULL REFERENCES retail.loyalty_cards(id),
|
||||
|
||||
-- Tipo
|
||||
transaction_type VARCHAR(20) NOT NULL, -- earn, redeem, expire, adjust
|
||||
points INTEGER NOT NULL,
|
||||
|
||||
-- Referencia
|
||||
order_id UUID REFERENCES retail.pos_orders(id),
|
||||
description TEXT,
|
||||
|
||||
-- Balance después de la transacción
|
||||
balance_after INTEGER NOT NULL,
|
||||
|
||||
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
|
||||
created_by UUID REFERENCES auth.users(id)
|
||||
);
|
||||
|
||||
-- ============================================================================
|
||||
-- ÍNDICES
|
||||
-- ============================================================================
|
||||
|
||||
-- Branches
|
||||
CREATE INDEX IF NOT EXISTS idx_branches_tenant ON retail.branches(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_branches_company ON retail.branches(company_id);
|
||||
|
||||
-- Cash registers
|
||||
CREATE INDEX IF NOT EXISTS idx_cash_registers_tenant ON retail.cash_registers(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_cash_registers_branch ON retail.cash_registers(branch_id);
|
||||
|
||||
-- POS sessions
|
||||
CREATE INDEX IF NOT EXISTS idx_pos_sessions_tenant ON retail.pos_sessions(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_pos_sessions_branch ON retail.pos_sessions(branch_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_pos_sessions_user ON retail.pos_sessions(user_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_pos_sessions_status ON retail.pos_sessions(status);
|
||||
CREATE INDEX IF NOT EXISTS idx_pos_sessions_date ON retail.pos_sessions(opening_date);
|
||||
|
||||
-- POS orders
|
||||
CREATE INDEX IF NOT EXISTS idx_pos_orders_tenant ON retail.pos_orders(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_pos_orders_session ON retail.pos_orders(session_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_pos_orders_branch ON retail.pos_orders(branch_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_pos_orders_customer ON retail.pos_orders(customer_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_pos_orders_date ON retail.pos_orders(order_date);
|
||||
CREATE INDEX IF NOT EXISTS idx_pos_orders_status ON retail.pos_orders(status);
|
||||
|
||||
-- POS order lines
|
||||
CREATE INDEX IF NOT EXISTS idx_pos_order_lines_tenant ON retail.pos_order_lines(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_pos_order_lines_order ON retail.pos_order_lines(order_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_pos_order_lines_product ON retail.pos_order_lines(product_id);
|
||||
|
||||
-- POS payments
|
||||
CREATE INDEX IF NOT EXISTS idx_pos_payments_tenant ON retail.pos_payments(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_pos_payments_order ON retail.pos_payments(order_id);
|
||||
|
||||
-- Cash movements
|
||||
CREATE INDEX IF NOT EXISTS idx_cash_movements_tenant ON retail.cash_movements(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_cash_movements_session ON retail.cash_movements(session_id);
|
||||
|
||||
-- Branch stock
|
||||
CREATE INDEX IF NOT EXISTS idx_branch_stock_tenant ON retail.branch_stock(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_branch_stock_branch ON retail.branch_stock(branch_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_branch_stock_product ON retail.branch_stock(product_id);
|
||||
|
||||
-- Stock transfers
|
||||
CREATE INDEX IF NOT EXISTS idx_stock_transfers_tenant ON retail.stock_transfers(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_stock_transfers_source ON retail.stock_transfers(source_branch_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_stock_transfers_dest ON retail.stock_transfers(destination_branch_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_stock_transfers_status ON retail.stock_transfers(status);
|
||||
|
||||
-- Product barcodes
|
||||
CREATE INDEX IF NOT EXISTS idx_product_barcodes_tenant ON retail.product_barcodes(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_product_barcodes_barcode ON retail.product_barcodes(barcode);
|
||||
CREATE INDEX IF NOT EXISTS idx_product_barcodes_product ON retail.product_barcodes(product_id);
|
||||
|
||||
-- Promotions
|
||||
CREATE INDEX IF NOT EXISTS idx_promotions_tenant ON retail.promotions(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_promotions_dates ON retail.promotions(start_date, end_date);
|
||||
CREATE INDEX IF NOT EXISTS idx_promotions_active ON retail.promotions(is_active);
|
||||
|
||||
-- Loyalty
|
||||
CREATE INDEX IF NOT EXISTS idx_loyalty_cards_tenant ON retail.loyalty_cards(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_loyalty_cards_customer ON retail.loyalty_cards(customer_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_loyalty_transactions_tenant ON retail.loyalty_transactions(tenant_id);
|
||||
CREATE INDEX IF NOT EXISTS idx_loyalty_transactions_card ON retail.loyalty_transactions(card_id);
|
||||
|
||||
-- ============================================================================
|
||||
-- ROW LEVEL SECURITY
|
||||
-- ============================================================================
|
||||
|
||||
ALTER TABLE retail.branches ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE retail.cash_registers ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE retail.pos_sessions ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE retail.pos_orders ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE retail.pos_order_lines ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE retail.pos_payments ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE retail.cash_movements ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE retail.branch_stock ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE retail.stock_transfers ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE retail.stock_transfer_lines ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE retail.product_barcodes ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE retail.promotions ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE retail.promotion_products ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE retail.loyalty_programs ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE retail.loyalty_cards ENABLE ROW LEVEL SECURITY;
|
||||
ALTER TABLE retail.loyalty_transactions ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
-- Políticas de aislamiento por tenant
|
||||
DO $$ BEGIN
|
||||
DROP POLICY IF EXISTS tenant_isolation_branches ON retail.branches;
|
||||
CREATE POLICY tenant_isolation_branches ON retail.branches
|
||||
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
EXCEPTION WHEN undefined_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
DROP POLICY IF EXISTS tenant_isolation_cash_registers ON retail.cash_registers;
|
||||
CREATE POLICY tenant_isolation_cash_registers ON retail.cash_registers
|
||||
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
EXCEPTION WHEN undefined_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
DROP POLICY IF EXISTS tenant_isolation_pos_sessions ON retail.pos_sessions;
|
||||
CREATE POLICY tenant_isolation_pos_sessions ON retail.pos_sessions
|
||||
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
EXCEPTION WHEN undefined_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
DROP POLICY IF EXISTS tenant_isolation_pos_orders ON retail.pos_orders;
|
||||
CREATE POLICY tenant_isolation_pos_orders ON retail.pos_orders
|
||||
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
EXCEPTION WHEN undefined_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
DROP POLICY IF EXISTS tenant_isolation_pos_order_lines ON retail.pos_order_lines;
|
||||
CREATE POLICY tenant_isolation_pos_order_lines ON retail.pos_order_lines
|
||||
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
EXCEPTION WHEN undefined_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
DROP POLICY IF EXISTS tenant_isolation_pos_payments ON retail.pos_payments;
|
||||
CREATE POLICY tenant_isolation_pos_payments ON retail.pos_payments
|
||||
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
EXCEPTION WHEN undefined_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
DROP POLICY IF EXISTS tenant_isolation_cash_movements ON retail.cash_movements;
|
||||
CREATE POLICY tenant_isolation_cash_movements ON retail.cash_movements
|
||||
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
EXCEPTION WHEN undefined_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
DROP POLICY IF EXISTS tenant_isolation_branch_stock ON retail.branch_stock;
|
||||
CREATE POLICY tenant_isolation_branch_stock ON retail.branch_stock
|
||||
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
EXCEPTION WHEN undefined_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
DROP POLICY IF EXISTS tenant_isolation_stock_transfers ON retail.stock_transfers;
|
||||
CREATE POLICY tenant_isolation_stock_transfers ON retail.stock_transfers
|
||||
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
EXCEPTION WHEN undefined_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
DROP POLICY IF EXISTS tenant_isolation_stock_transfer_lines ON retail.stock_transfer_lines;
|
||||
CREATE POLICY tenant_isolation_stock_transfer_lines ON retail.stock_transfer_lines
|
||||
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
EXCEPTION WHEN undefined_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
DROP POLICY IF EXISTS tenant_isolation_product_barcodes ON retail.product_barcodes;
|
||||
CREATE POLICY tenant_isolation_product_barcodes ON retail.product_barcodes
|
||||
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
EXCEPTION WHEN undefined_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
DROP POLICY IF EXISTS tenant_isolation_promotions ON retail.promotions;
|
||||
CREATE POLICY tenant_isolation_promotions ON retail.promotions
|
||||
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
EXCEPTION WHEN undefined_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
DROP POLICY IF EXISTS tenant_isolation_promotion_products ON retail.promotion_products;
|
||||
CREATE POLICY tenant_isolation_promotion_products ON retail.promotion_products
|
||||
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
EXCEPTION WHEN undefined_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
DROP POLICY IF EXISTS tenant_isolation_loyalty_programs ON retail.loyalty_programs;
|
||||
CREATE POLICY tenant_isolation_loyalty_programs ON retail.loyalty_programs
|
||||
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
EXCEPTION WHEN undefined_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
DROP POLICY IF EXISTS tenant_isolation_loyalty_cards ON retail.loyalty_cards;
|
||||
CREATE POLICY tenant_isolation_loyalty_cards ON retail.loyalty_cards
|
||||
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
EXCEPTION WHEN undefined_object THEN NULL; END $$;
|
||||
|
||||
DO $$ BEGIN
|
||||
DROP POLICY IF EXISTS tenant_isolation_loyalty_transactions ON retail.loyalty_transactions;
|
||||
CREATE POLICY tenant_isolation_loyalty_transactions ON retail.loyalty_transactions
|
||||
FOR ALL USING (tenant_id = current_setting('app.current_tenant_id', true)::UUID);
|
||||
EXCEPTION WHEN undefined_object THEN NULL; END $$;
|
||||
|
||||
-- ============================================================================
|
||||
-- COMENTARIOS
|
||||
-- ============================================================================
|
||||
|
||||
COMMENT ON TABLE retail.branches IS 'Sucursales de la empresa';
|
||||
COMMENT ON TABLE retail.cash_registers IS 'Cajas registradoras por sucursal';
|
||||
COMMENT ON TABLE retail.pos_sessions IS 'Sesiones de punto de venta';
|
||||
COMMENT ON TABLE retail.pos_orders IS 'Órdenes/Ventas de punto de venta';
|
||||
COMMENT ON TABLE retail.pos_order_lines IS 'Líneas de venta';
|
||||
COMMENT ON TABLE retail.pos_payments IS 'Pagos de orden (para pagos mixtos)';
|
||||
COMMENT ON TABLE retail.cash_movements IS 'Entradas/salidas de efectivo';
|
||||
COMMENT ON TABLE retail.branch_stock IS 'Stock por sucursal';
|
||||
COMMENT ON TABLE retail.stock_transfers IS 'Transferencias entre sucursales';
|
||||
COMMENT ON TABLE retail.stock_transfer_lines IS 'Líneas de transferencia';
|
||||
COMMENT ON TABLE retail.product_barcodes IS 'Códigos de barras múltiples por producto';
|
||||
COMMENT ON TABLE retail.promotions IS 'Promociones y descuentos';
|
||||
COMMENT ON TABLE retail.promotion_products IS 'Productos en promoción';
|
||||
COMMENT ON TABLE retail.loyalty_programs IS 'Programas de fidelización';
|
||||
COMMENT ON TABLE retail.loyalty_cards IS 'Tarjetas de fidelización';
|
||||
COMMENT ON TABLE retail.loyalty_transactions IS 'Transacciones de puntos';
|
||||
|
||||
-- ============================================================================
|
||||
-- FIN TABLAS RETAIL
|
||||
-- Total: 16 tablas, 6 ENUMs
|
||||
-- ============================================================================
|
||||
Loading…
Reference in New Issue
Block a user