Guía Drizzle + schema OneBusiness. Invocar al tocar DB: tablas, enums, queries, migraciones, transacciones e índices.
src/lib/drizzle.tssrc/lib/db.ts (importar db desde aquí)rolEnum: Dueño | Socio | Admin | ExternotipoCuentaEnum: EFECTIVO | BANCARIA | CAJA_CHICAtipoMovimientoEnum: INGRESO | EGRESO | TRASPASO_SALIDA | TRASPASO_ENTRADAestadoMovimientoEnum: PENDIENTE | APROBADO | RECHAZADO | PAGADO | CANCELADOtipoCategoriaEnum: INGRESO | EGRESOestadoCotizacionEnum: BORRADOR | ENVIADA | APROBADA | FACTURADA | CANCELADAnegocios:
tieneDivisiones (controla obligatoriedad de centroCostoId en movimientos)umbralAlerta, umbralCritico (semaforo)activocentrosCosto:
padreId (self-ref), tipo, descripcion, negocioId, activocategorias:
negocioId nullable (null = global)requiereAprobacion, montoMaxSinAprobacion, activacuentasBanco:
negocioId nullableesGlobal (true = visible en todos los negocios)cuentaNegociocuentaNegocio (N:M):
cuentaId, negocioId, fechaAsignacion, unique index (uq_cuenta_negocio)movimientos:
negocioId NOT NULLcentroCostoId nullable (según negocios.tieneDivisiones)categoriaId nullablePENDIENTE/APROBADO/RECHAZADO/PAGADO/CANCELADOefectuado, fechaPago, pagadoPortraspasoRefId (vínculo a espejo)auditLogs: bitácora de auditoría (evento, recurso, userId, negocioId, detalles JSON string)cotizaciones / cotizacionItemsroles, usuarios, usuarioNegocioimport { db } from '@/lib/db';
import {
usuarios,
negocios,
usuarioNegocio,
cuentasBanco,
cuentaNegocio,
categorias,
centrosCosto,
movimientos,
cotizaciones,
cotizacionItems,
auditLogs,
} from '@/lib/drizzle';
import {
eq,
and,
or,
gte,
lte,
like,
ilike,
inArray,
isNull,
isNotNull,
desc,
asc,
sql,
count,
} from 'drizzle-orm';
Select básico
await db
.select()
.from(movimientos)
.where(and(eq(movimientos.negocioId, negocioId), eq(movimientos.activo, true)))
.orderBy(desc(movimientos.createdAt));
Join
await db
.select({
movimiento: movimientos,
cuenta: { nombre: cuentasBanco.nombre },
})
.from(movimientos)
.leftJoin(cuentasBanco, eq(movimientos.cuentaBancoId, cuentasBanco.id))
.where(eq(movimientos.negocioId, negocioId));
Transacción (obligatoria)
await db.transaction(async (tx) => {
const [mov1] = await tx.insert(movimientos).values({ ... }).returning();
const [mov2] = await tx.insert(movimientos).values({ traspasoRefId: mov1.id, ... }).returning();
return { mov1, mov2 };
});
Paginación (listado + total)
const [items, [{ total }]] = await Promise.all([
db.select().from(movimientos).where(conditions).limit(limit).offset((page - 1) * limit),
db.select({ total: count() }).from(movimientos).where(conditions),
]);
drizzle.ts → npm run db:generate → npm run db:migrate → npm run build.estado = 'PAGADO' suma/resta movimientos.estado IN ('APROBADO','PAGADO') (ver ESTADOS_EJECUTADOS en src/services/reporte.service.ts).