93 lines
3.5 KiB
TypeScript
93 lines
3.5 KiB
TypeScript
import { BadRequestException, Injectable, NotFoundException } from "@nestjs/common";
|
|
import { PrismaService } from "../../prisma/prisma.service";
|
|
|
|
@Injectable()
|
|
export class CalendarService {
|
|
constructor(private readonly prisma: PrismaService) {}
|
|
|
|
routingForms(tenantId: string) {
|
|
return this.prisma.calendarRoutingForm.findMany({
|
|
where: { tenantId },
|
|
orderBy: { createdAt: "desc" },
|
|
include: { event: true, _count: { select: { slots: true, bookings: true } } }
|
|
});
|
|
}
|
|
|
|
createRoutingForm(tenantId: string, payload: any) {
|
|
return this.prisma.calendarRoutingForm.create({
|
|
data: {
|
|
tenantId,
|
|
eventId: payload.eventId || null,
|
|
name: String(payload.name ?? ""),
|
|
slug: String(payload.slug ?? "").toLowerCase().trim(),
|
|
description: payload.description ? String(payload.description) : null,
|
|
durationMinutes: Number(payload.durationMinutes ?? 30),
|
|
active: payload.active === undefined ? true : Boolean(payload.active)
|
|
}
|
|
});
|
|
}
|
|
|
|
slots(tenantId: string, routingFormId?: string) {
|
|
return this.prisma.calendarSlot.findMany({
|
|
where: { tenantId, ...(routingFormId ? { routingFormId } : {}) },
|
|
orderBy: { startsAt: "asc" },
|
|
include: { routingForm: true }
|
|
});
|
|
}
|
|
|
|
async createSlot(tenantId: string, payload: any) {
|
|
const routingForm = await this.prisma.calendarRoutingForm.findFirst({ where: { tenantId, id: String(payload.routingFormId ?? "") } });
|
|
if (!routingForm) throw new NotFoundException("Routing form not found");
|
|
const startsAt = new Date(String(payload.startsAt ?? ""));
|
|
const endsAt = new Date(String(payload.endsAt ?? ""));
|
|
if (!Number.isFinite(startsAt.getTime()) || !Number.isFinite(endsAt.getTime()) || endsAt <= startsAt) {
|
|
throw new BadRequestException("Invalid slot time");
|
|
}
|
|
return this.prisma.calendarSlot.create({
|
|
data: {
|
|
tenantId,
|
|
routingFormId: routingForm.id,
|
|
startsAt,
|
|
endsAt,
|
|
capacity: Number(payload.capacity ?? 1),
|
|
active: payload.active === undefined ? true : Boolean(payload.active)
|
|
},
|
|
include: { routingForm: true }
|
|
});
|
|
}
|
|
|
|
bookings(tenantId: string) {
|
|
return this.prisma.booking.findMany({
|
|
where: { tenantId },
|
|
orderBy: { startsAt: "desc" },
|
|
include: { routingForm: true, event: true, attendee: true }
|
|
});
|
|
}
|
|
|
|
async createBooking(tenantId: string, payload: any) {
|
|
const routingForm = await this.prisma.calendarRoutingForm.findFirst({ where: { tenantId, id: String(payload.routingFormId ?? "") } });
|
|
if (!routingForm) throw new NotFoundException("Routing form not found");
|
|
const startsAt = new Date(String(payload.startsAt ?? ""));
|
|
const endsAt = new Date(String(payload.endsAt ?? ""));
|
|
if (!Number.isFinite(startsAt.getTime()) || !Number.isFinite(endsAt.getTime()) || endsAt <= startsAt) {
|
|
throw new BadRequestException("Invalid booking time");
|
|
}
|
|
return this.prisma.booking.create({
|
|
data: {
|
|
tenantId,
|
|
routingFormId: routingForm.id,
|
|
eventId: payload.eventId || routingForm.eventId || null,
|
|
attendeeId: payload.attendeeId || null,
|
|
fullName: String(payload.fullName ?? ""),
|
|
email: String(payload.email ?? "").toLowerCase().trim(),
|
|
phone: payload.phone ? String(payload.phone) : null,
|
|
startsAt,
|
|
endsAt,
|
|
status: payload.status ? String(payload.status) : "booked",
|
|
notes: payload.notes ? String(payload.notes) : null
|
|
},
|
|
include: { routingForm: true, event: true, attendee: true }
|
|
});
|
|
}
|
|
}
|