import { pool } from "../db/pool.ts"; import { runMigrations } from "../db/migrate.ts"; export interface SeedIds { businessId: number; ownerUserId: number; employeeUserId: number; employeeId: number; serviceId: number; clientId: number; } const WORKING_HOURS = JSON.stringify({ 1: { start: "09:00", end: "20:00" }, 2: { start: "09:00", end: "20:00" }, 3: { start: "09:00", end: "20:00" }, 4: { start: "09:00", end: "20:00" }, 5: { start: "09:00", end: "20:00" }, 6: { start: "10:00", end: "18:00" }, 7: null, }); /** * Vacía el esquema. La guarda del nombre no es decorativa: este DROP SCHEMA * contra la base de desarrollo se llevaría los datos del spa por delante. */ export async function dropSchema(): Promise { if (!/yola_test/.test(process.env.DATABASE_URL || "")) { throw new Error("dropSchema solo corre contra yola_test — revisa DATABASE_URL"); } await pool.query(`DROP SCHEMA public CASCADE; CREATE SCHEMA public;`); } /** Deja la base vacía y con el esquema al día. */ export async function resetDb(): Promise { await dropSchema(); await runMigrations(); } export async function seedMinimal(): Promise { const biz = await pool.query( `INSERT INTO businesses (name, slug, working_hours) VALUES ('Yola Franco Spa', 'yola-franco', $1::jsonb) RETURNING id`, [WORKING_HOURS] ); const businessId = biz.rows[0].id as number; const emp = await pool.query( `INSERT INTO employees (business_id, name, email) VALUES ($1,'Karla Ruiz','karla@yola.mx') RETURNING id`, [businessId] ); const employeeId = emp.rows[0].id as number; const svc = await pool.query( `INSERT INTO services (business_id, name, duration_min, price) VALUES ($1,'Extensiones de pestañas',90,850) RETURNING id`, [businessId] ); const serviceId = svc.rows[0].id as number; await pool.query( `INSERT INTO employee_services (employee_id, service_id) VALUES ($1,$2)`, [employeeId, serviceId] ); const owner = await pool.query( `INSERT INTO users (business_id, email, password, name, role) VALUES ($1,'yola@yola.mx','demo1234','Yola Franco','owner') RETURNING id`, [businessId] ); const empUser = await pool.query( `INSERT INTO users (business_id, email, password, name, role, employee_id) VALUES ($1,'karla@yola.mx','demo1234','Karla Ruiz','employee',$2) RETURNING id`, [businessId, employeeId] ); const cli = await pool.query( `INSERT INTO clients (business_id, name, phone, phone_e164) VALUES ($1,'Mariana López','55 8888 7777','+525588887777') RETURNING id`, [businessId] ); return { businessId, ownerUserId: owner.rows[0].id, employeeUserId: empUser.rows[0].id, employeeId, serviceId, clientId: cli.rows[0].id, }; } /** * Crea un negocio suelto, sin catálogo ni personal. * * `seedMinimal` siembra UN negocio completo y sirve para casi todo; esto existe * para las pruebas multi-negocio, donde lo que se comprueba es justamente que * dos cuentas no se pisan y no hace falta el resto del inventario. */ export async function crearNegocio( opts: { name?: string; slug?: string } = {} ): Promise<{ id: number; name: string }> { const name = opts.name ?? `Negocio ${Math.random().toString(36).slice(2, 8)}`; const slug = opts.slug ?? name.toLowerCase().replace(/[^a-z0-9]+/g, "-"); const { rows } = await pool.query( `INSERT INTO businesses (name, slug, working_hours) VALUES ($1, $2, $3::jsonb) RETURNING id, name`, [name, slug, WORKING_HOURS] ); return rows[0]; }