- 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>
65 lines
2.9 KiB
PL/PgSQL
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());
|