Cliente now picks a jefe mecánico after choosing the service so the calendar shows that specific jefe's availability. Each jefe has its own configurable parallel slot capacity (replacing the global SLOTS_PARALELOS = 5). Admins manage jefes from /admin/jefes; jefes log in to /jefe to see their daily agenda. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+29
-7
@@ -1,6 +1,5 @@
|
||||
import { prisma } from "./prisma";
|
||||
|
||||
const SLOTS_PARALELOS = 5;
|
||||
const INICIO_H = 8;
|
||||
const INICIO_M = 30;
|
||||
const FIN_H = 17;
|
||||
@@ -51,9 +50,14 @@ function horasDentroDeJornada(inicio: Date, fin: Date): boolean {
|
||||
return mismodia && iMin >= INICIO_MINUTOS && fMin <= FIN_MINUTOS;
|
||||
}
|
||||
|
||||
async function turnosSolapados(inicio: Date, fin: Date): Promise<number> {
|
||||
async function turnosSolapados(
|
||||
inicio: Date,
|
||||
fin: Date,
|
||||
jefeMecanicoId: string
|
||||
): Promise<number> {
|
||||
const count = await prisma.turno.count({
|
||||
where: {
|
||||
jefeMecanicoId,
|
||||
estado: { in: ["PENDIENTE", "CONFIRMADO"] },
|
||||
AND: [{ fechaInicio: { lt: fin } }, { fechaFin: { gt: inicio } }],
|
||||
},
|
||||
@@ -61,16 +65,28 @@ async function turnosSolapados(inicio: Date, fin: Date): Promise<number> {
|
||||
return count;
|
||||
}
|
||||
|
||||
async function obtenerJefeActivo(jefeMecanicoId: string) {
|
||||
return prisma.jefeMecanico.findUnique({
|
||||
where: { id: jefeMecanicoId },
|
||||
select: { slotsParalelos: true, activo: true },
|
||||
});
|
||||
}
|
||||
|
||||
export interface SlotDisponible {
|
||||
fechaInicio: Date;
|
||||
fechaFin: Date;
|
||||
}
|
||||
|
||||
export async function obtenerSlotsDisponibles(
|
||||
jefeMecanicoId: string,
|
||||
duracionHoras: number,
|
||||
diasAdelante = 14,
|
||||
limite = 300
|
||||
): Promise<SlotDisponible[]> {
|
||||
const jefe = await obtenerJefeActivo(jefeMecanicoId);
|
||||
if (!jefe || !jefe.activo) return [];
|
||||
const cap = jefe.slotsParalelos;
|
||||
|
||||
const slots: SlotDisponible[] = [];
|
||||
const ahora = new Date();
|
||||
const duracionMs = duracionHoras * 60 * 60 * 1000;
|
||||
@@ -103,8 +119,8 @@ export async function obtenerSlotsDisponibles(
|
||||
continue;
|
||||
}
|
||||
|
||||
const ocupados = await turnosSolapados(cursor, fin);
|
||||
if (ocupados < SLOTS_PARALELOS) {
|
||||
const ocupados = await turnosSolapados(cursor, fin, jefeMecanicoId);
|
||||
if (ocupados < cap) {
|
||||
slots.push({ fechaInicio: new Date(cursor), fechaFin: new Date(fin) });
|
||||
}
|
||||
|
||||
@@ -114,8 +130,14 @@ export async function obtenerSlotsDisponibles(
|
||||
return slots;
|
||||
}
|
||||
|
||||
export async function slotEstaDisponible(inicio: Date, fin: Date): Promise<boolean> {
|
||||
export async function slotEstaDisponible(
|
||||
inicio: Date,
|
||||
fin: Date,
|
||||
jefeMecanicoId: string
|
||||
): Promise<boolean> {
|
||||
if (!esDiaHabil(inicio) || !horasDentroDeJornada(inicio, fin)) return false;
|
||||
const ocupados = await turnosSolapados(inicio, fin);
|
||||
return ocupados < SLOTS_PARALELOS;
|
||||
const jefe = await obtenerJefeActivo(jefeMecanicoId);
|
||||
if (!jefe || !jefe.activo) return false;
|
||||
const ocupados = await turnosSolapados(inicio, fin, jefeMecanicoId);
|
||||
return ocupados < jefe.slotsParalelos;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user