Files
CrmClinicas/supabase/migrations/006_inventory.sql
Consultoria AS 79b5d86325 feat: CRM Clinicas SaaS - MVP completo
- Auth: Login/Register con creacion de clinica
- Dashboard: KPIs reales, graficas recharts
- Pacientes: CRUD completo con busqueda
- Agenda: FullCalendar, drag-and-drop, vista recepcion
- Expediente: Notas SOAP, signos vitales, CIE-10
- Facturacion: Facturas con IVA, campos CFDI SAT
- Inventario: Productos, stock, movimientos, alertas
- Configuracion: Clinica, equipo, catalogo servicios
- Supabase self-hosted: 18 tablas con RLS multi-tenant
- Docker + Nginx para produccion

Co-Authored-By: claude-flow <ruv@ruv.net>
2026-03-03 07:04:14 +00:00

65 lines
2.9 KiB
PL/PgSQL

CREATE TABLE products (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
clinic_id UUID NOT NULL REFERENCES clinics(id) ON DELETE CASCADE,
sku TEXT,
name TEXT NOT NULL,
description TEXT,
category TEXT NOT NULL DEFAULT 'insumo' CHECK (category IN ('medicamento','insumo','material','equipo')),
unit TEXT NOT NULL DEFAULT 'pieza',
purchase_price DECIMAL(10,2) NOT NULL DEFAULT 0,
sale_price DECIMAL(10,2) NOT NULL DEFAULT 0,
min_stock INT NOT NULL DEFAULT 0,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
ALTER TABLE invoice_items ADD CONSTRAINT fk_invoice_items_product FOREIGN KEY (product_id) REFERENCES products(id);
CREATE TABLE inventory_stock (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
clinic_id UUID NOT NULL REFERENCES clinics(id) ON DELETE CASCADE,
product_id UUID NOT NULL REFERENCES products(id) ON DELETE CASCADE,
current_stock DECIMAL(10,2) NOT NULL DEFAULT 0,
last_updated TIMESTAMPTZ NOT NULL DEFAULT NOW(),
UNIQUE(clinic_id, product_id)
);
CREATE TABLE inventory_movements (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
clinic_id UUID NOT NULL REFERENCES clinics(id) ON DELETE CASCADE,
product_id UUID NOT NULL REFERENCES products(id) ON DELETE CASCADE,
type TEXT NOT NULL CHECK (type IN ('entrada','salida','ajuste','merma')),
quantity DECIMAL(10,2) NOT NULL,
reason TEXT,
reference_id TEXT,
created_by UUID REFERENCES users(id),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX idx_movements_product ON inventory_movements(product_id, created_at DESC);
CREATE OR REPLACE FUNCTION update_inventory_stock()
RETURNS TRIGGER AS $$
BEGIN
INSERT INTO inventory_stock (clinic_id, product_id, current_stock, last_updated)
VALUES (NEW.clinic_id, NEW.product_id, NEW.quantity, NOW())
ON CONFLICT (clinic_id, product_id)
DO UPDATE SET current_stock = inventory_stock.current_stock + NEW.quantity, last_updated = NOW();
RETURN NEW;
END;
$$ LANGUAGE plpgsql SECURITY DEFINER;
CREATE TRIGGER trg_update_stock AFTER INSERT ON inventory_movements FOR EACH ROW EXECUTE FUNCTION update_inventory_stock();
ALTER TABLE products ENABLE ROW LEVEL SECURITY;
CREATE POLICY "View clinic products" ON products FOR SELECT USING (clinic_id = auth.clinic_id());
CREATE POLICY "Manage clinic products" ON products FOR ALL USING (clinic_id = auth.clinic_id());
ALTER TABLE inventory_stock ENABLE ROW LEVEL SECURITY;
CREATE POLICY "View clinic stock" ON inventory_stock FOR SELECT USING (clinic_id = auth.clinic_id());
CREATE POLICY "Manage clinic stock" ON inventory_stock FOR ALL USING (clinic_id = auth.clinic_id());
ALTER TABLE inventory_movements ENABLE ROW LEVEL SECURITY;
CREATE POLICY "View clinic movements" ON inventory_movements FOR SELECT USING (clinic_id = auth.clinic_id());
CREATE POLICY "Insert clinic movements" ON inventory_movements FOR INSERT WITH CHECK (clinic_id = auth.clinic_id());