Contracts — Módulo temporal compartido (lib/ventanas.ts)
Sin endpoints ni tablas (006 FR-011). Estos contratos son firmas TypeScript puras que las specs consumidoras referencian por nombre (006 FR-010). Zona Europe/Madrid, precisión de minuto, textos es-ES. Implementación apoyada en lib/tiempo.ts (ZONA_HORARIA, truncarAMinuto, formatear*, aMinutos) e lib/instantes.ts (instanteLocal).
/** Captura única por operación (FR-001/FR-002). Reloj del servidor, truncado a minuto. */
export function capturarAhora(fecha?: Date): Date;
/** FR-004 RN2. true ⇔ inicio estrictamente anterior a ahora. Igual ⇒ false. */
export function esPasado(inicio: Date, ahora: Date): boolean;
/** FR-005. true ⇔ inicio − ahora ≥ 24 h (borde incluido, sin tope). */
export function cancelacionEnPlazo(inicio: Date, ahora: Date): boolean;
/** FR-006. true ⇔ 24 h ≤ inicio − ejecucion ≤ 48 h (ambos incluidos). */
export function enVentanaRecordatorios(inicio: Date, ejecucion: Date): boolean;
export type SemanaEtiquetada = { n: 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8; inicio: Date; fin: Date; etiqueta: string };
// etiqueta = `S-N: DD/MM/AAAA–DD/MM/AAAA` derivada de la ventana (FR-009, Q4/A).
/**
* FR-007. Semana en curso = semana natural lunes–domingo
* que contiene `hoy` en Europe/Madrid, recalculada en cada llamada; devuelve las 8
* anteriores cerradas S-8 (más antigua) … S-1 (más reciente). La en curso nunca entra.
* `diasLaborables` no altera los bordes semanales (solo parametriza FR-008).
*/
export function semanasAnalitica(hoy: Date, diasLaborables?: number[]): SemanaEtiquetada[];
/** FR-008. Denominador con la configuración vigente; nunca la constante 26.400 salvo defecto. */
export function denominadorOcupacion(
jornadaInicio: string, // "HH:MM"
jornadaFin: string, // "HH:MM"
diasLaborables?: number[],
semanas?: number, // defecto 8
): { minutos: number; etiquetaJornada: string }; // e.g. { minutos: 26400, etiquetaJornada: "09:00–20:00, Lun–Vie" }
/** FR-009. Etiqueta de tramo Q4/A. Delega en formatearTramo existente. */
export function etiquetarTramo(inicio: Date, fin: Date): string; // "DD/MM/AAAA, HH:MM–HH:MM"
Reglas de uso (vinculantes para consumidoras)
- Cada operación captura
ahora = capturarAhora()una vez y lo propaga; prohibidonew Date(),now()oCURRENT_TIMESTAMPdentro de reglas de negocio, salvo dentro decapturarAhora()(FR-001/FR-010). - Toda entrada se trunca a minuto antes de comparar (FR-002).
- Ninguna consumidora redefine bordes ni ventanas; cita
006 FR-00Xpor nombre (FR-010). Una definición temporal fuera delib/(tiempo|ventanas).tses defecto. - La BD recibe el «ahora» como parámetro (Prisma); RN1-exclusión sigue en BD pero con valores ya truncados desde app.
diasLaborables: días ISO 1–7, defecto[1,2,3,4,5](enmienda S-06 aClinicade la 001).