Files
FRASA-CAS/apps/landing/src/components/desarrollos/generador.ts
Consult AS Technology d6548999bf feat(desarrollos): modulo de alta de desarrollos con inventario, reglas del cotizador por desarrollo y micrositio publico
Modulo nuevo (solo admin) para dar de alta desarrollos sin tocar codigo:
- CRUD de la ficha, modelos e inventario (alta manual y generador por rango)
- Reglas del cotizador por desarrollo, editables y persistidas en la BD
- El cotizador consume las reglas desde /desarrollos/reglas-cotizador y cae a
  las constantes con aviso cuando un desarrollo aun no tiene reglas guardadas
- Micrositio publico en /d/:clave (sin sesion) con ficha, modelos y
  disponibilidad; jamas expone datos de clientes ni cotizaciones

Integracion:
- La landing monta el modulo en el grid (clave 'desarrollos', solo admin) y el
  micrositio fuera del login; el rol manager NO accede (matriz y API con 403)
- La tabla de roles de Configuracion ahora lista todos los modulos
- Se alinea la FK de ReglaCotizadorDesarrollo con la BD viva (Desarrollo.id)

Verificado: 708 pruebas del API, 115 del cotizador y 89 de la landing en verde;
12/12 cotizaciones identicas antes y despues del cambio de reglas; prueba en
vivo del API con alta, modelos, inventario, reglas, micrositio y baja (30/30).
2026-09-21 09:52:47 +00:00

47 lines
1.8 KiB
TypeScript

/**
* Numeración de unidades: el patrón admite `{clave}` (clave del desarrollo) y
* `{n}` (número consecutivo del rango).
*/
export const MAX_UNIDADES_GENERADOR = 1000
export function aplicarPatron(patron: string, clave: string, n: number): string {
return patron.split('{clave}').join(clave).split('{n}').join(String(n))
}
/** Primeros `max` códigos del rango (vista previa antes de confirmar) */
export function generarCodigos(
patron: string,
clave: string,
desde: number,
hasta: number,
max = 5,
): string[] {
if (!patron.includes('{n}') || !Number.isInteger(desde) || !Number.isInteger(hasta) || hasta < desde) {
return []
}
const cantidad = Math.min(hasta - desde + 1, Math.max(0, max))
return Array.from({ length: cantidad }, (_, i) => aplicarPatron(patron, clave, desde + i))
}
/** Total de unidades que crearía el generador con el rango actual */
export function totalDelRango(desde: number, hasta: number): number {
if (!Number.isInteger(desde) || !Number.isInteger(hasta) || hasta < desde) return 0
return hasta - desde + 1
}
/** Devuelve el mensaje de error del generador o null si todo está bien */
export function validarGenerador(patron: string, desde: number, hasta: number): string | null {
if (patron.trim() === '') return 'Escribe el patrón de código de la unidad.'
if (!patron.includes('{n}')) return 'El patrón debe incluir {n} para numerar las unidades.'
if (/[^A-Za-z0-9{}_-]/.test(patron)) {
return 'El patrón solo admite letras, números, guiones, {clave} y {n}.'
}
if (!Number.isInteger(desde) || !Number.isInteger(hasta)) return 'El rango debe usar números enteros.'
if (hasta < desde) return 'El valor "hasta" debe ser mayor o igual que "desde".'
if (hasta - desde + 1 > MAX_UNIDADES_GENERADOR) {
return `El rango no puede superar ${MAX_UNIDADES_GENERADOR} unidades por vez.`
}
return null
}