import { db } from "@/db"; import { offer_macros, offer_micros, offer_services, offer_micro_services, } from "@/db/schema"; import type { OfferMacro, OfferMicro, OfferService } from "@/db/schema"; import { eq, asc, inArray, sql } from "drizzle-orm"; export type MicroWithServices = OfferMicro & { services: Array<{ id: string; name: string; price: string }>; cumulative_price: string; }; export type MacroWithMicros = OfferMacro & { micros: MicroWithServices[]; }; export async function getCatalogWithMicros(): Promise { const macros = await db .select() .from(offer_macros) .orderBy(asc(offer_macros.sort_order), asc(offer_macros.created_at)); if (macros.length === 0) return []; const macroIds = macros.map((m) => m.id); const micros = await db .select() .from(offer_micros) .where(inArray(offer_micros.macro_id, macroIds)) .orderBy(asc(offer_micros.sort_order)); const microIds = micros.map((m) => m.id); if (microIds.length === 0) { return macros.map((m) => ({ ...m, micros: [] })); } // Fetch junction rows + service data in one query const assignments = await db .select({ micro_id: offer_micro_services.micro_id, service_id: offer_services.id, name: offer_services.name, price: offer_services.price, }) .from(offer_micro_services) .innerJoin(offer_services, eq(offer_micro_services.service_id, offer_services.id)) .where(inArray(offer_micro_services.micro_id, microIds)); // Cumulative price per micro const cumulRows = await db .select({ micro_id: offer_micro_services.micro_id, cumulative_price: sql`coalesce(sum(${offer_services.price}::numeric), 0)`, }) .from(offer_micro_services) .innerJoin(offer_services, eq(offer_micro_services.service_id, offer_services.id)) .where(inArray(offer_micro_services.micro_id, microIds)) .groupBy(offer_micro_services.micro_id); const cumulMap = new Map(cumulRows.map((r) => [r.micro_id, r.cumulative_price])); const microsWithServices: MicroWithServices[] = micros.map((micro) => ({ ...micro, services: assignments .filter((a) => a.micro_id === micro.id) .map((a) => ({ id: a.service_id, name: a.name, price: String(a.price) })), cumulative_price: cumulMap.get(micro.id) ?? "0", })); return macros.map((macro) => ({ ...macro, micros: microsWithServices.filter((m) => m.macro_id === macro.id), })); } export async function getAllOfferServices(): Promise { return db .select() .from(offer_services) .where(eq(offer_services.active, true)) .orderBy(asc(offer_services.name)); } // Returns assigned service IDs for a given micro-offer (used by ServiceCheckboxList) export async function getMicroAssignedServiceIds(microId: string): Promise { const rows = await db .select({ service_id: offer_micro_services.service_id }) .from(offer_micro_services) .where(eq(offer_micro_services.micro_id, microId)); return rows.map((r) => r.service_id); }