// ROCA GOLF — shared data adapted to real SQL schema (oc_compras) const { useState, useEffect, useMemo, useRef } = React; const ROCA_USER = { name: "Mariana Vega", role: "Contralor", initials: "MV" }; const DEFAULT_THRESHOLDS = { warn: 80, alert: 90, over: 100 }; // ───────────────────────── PROYECTOS (proyectos) ───────────────────────── // Refleja los proyectos reales de la BD (tabla: proyectos). presupuesto/ejercido // son valores de referencia — Phase 3 los calculará desde ordenes_compra. const PROYECTOS = [ { id: 27, clave: "G2511", empresa: "AVR GOLF DEL CARIBE", nombre: "VALLE DE LOS ENCINOS", ubicacion: "Chihuahua, MEX.", cliente: "Valle de los Encinos", moneda: "MXN", activo: true, inicio: "2026-04-01", fin: "2026-09-30", presupuesto: 2500000, ejercido: 1320000, color: "#1a4d2e" }, { id: 28, clave: "G2603", empresa: "AVR GOLF DEL CARIBE", nombre: "LAS RIBERAS", ubicacion: "Hermosillo, Sonora", cliente: "Las Riberas", moneda: "MXN", activo: true, inicio: "2026-04-01", fin: "2026-10-31", presupuesto: 1500000, ejercido: 412000, color: "#c9a961" }, { id: 1, clave: "G2512M", empresa: "AVR GOLF CORPORATIVO", nombre: "CC MONTERREY MITRAS", ubicacion: "Monterrey, N.L.", cliente: "Club Campestre Monterrey Mitras", moneda: "MXN", activo: true, inicio: "2026-04-01", fin: "2026-08-30", presupuesto: 800000, ejercido: 310000, color: "#2d6a44" }, { id: 2, clave: "G2512P", empresa: "AVR GOLF CORPORATIVO", nombre: "CC MONTERREY PRESA", ubicacion: "Monterrey, N.L.", cliente: "Club Campestre Monterrey Presa", moneda: "MXN", activo: true, inicio: "2026-04-01", fin: "2026-08-30", presupuesto: 1200000, ejercido: 282000, color: "#a88838" }, { id: 24, clave: "G2020.O", empresa: "AVR GOLF DEL CARIBE", nombre: "OFICINA CENTRAL", ubicacion: "Cancún, Q. Roo", cliente: "Oficina Central", moneda: "MXN", activo: true, inicio: "2026-01-01", fin: "2026-12-31", presupuesto: 360000, ejercido: 196000, color: "#4a8a63" } ]; // Tareas Gantt: cada fila es un insumo dentro de un proyecto, con ventana de uso, monto y progreso // proyectoid = ID real de la tabla proyectos en la BD const GANTT_TAREAS = [ // Proyecto 27 — VALLE DE LOS ENCINOS { id: 101, proyectoid: 27, clave: "01-0101", desc: "Fletes de maquinaria", inicio: "2026-04-01", fin: "2026-04-28", monto: 84320, progreso: 100, statuspago: "PAGADO" }, { id: 102, proyectoid: 27, clave: "02-0201", desc: "Varillas de acero corrugado", inicio: "2026-04-10", fin: "2026-05-08", monto: 48000, progreso: 75, statuspago: "PENDIENTE" }, { id: 103, proyectoid: 27, clave: "03-0101", desc: "Nómina quincenal", inicio: "2026-04-18", fin: "2026-05-22", monto: 36000, progreso: 45, statuspago: "PAGO_PARCIAL" }, { id: 104, proyectoid: 27, clave: "04-0101", desc: "Backhoe CAT 416E", inicio: "2026-04-26", fin: "2026-06-12", monto: 21800, progreso: 8, statuspago: "PENDIENTE" }, // Proyecto 28 — LAS RIBERAS { id: 201, proyectoid: 28, clave: "02-0401", desc: "Geomembrana PVC", inicio: "2026-04-08", fin: "2026-05-30", monto: 56400, progreso: 60, statuspago: "PAGO_PARCIAL" }, { id: 202, proyectoid: 28, clave: "02-0402", desc: "Geotextil", inicio: "2026-04-12", fin: "2026-05-30", monto: 75000, progreso: 50, statuspago: "PAGO_PARCIAL" }, { id: 203, proyectoid: 28, clave: "01-0301", desc: "Renta de sanitarios portátiles", inicio: "2026-04-15", fin: "2026-05-25", monto: 32500, progreso: 70, statuspago: "PAGADO" }, // Proyecto 1 — CC MONTERREY MITRAS { id: 301, proyectoid: 1, clave: "02-0403", desc: "Dominant plus, Flagstick, Tyee", inicio: "2026-04-15", fin: "2026-05-20", monto: 64000, progreso: 40, statuspago: "PAGADO" }, { id: 302, proyectoid: 1, clave: "04-0101", desc: "Backhoe CAT 416E — segunda partida", inicio: "2026-04-23", fin: "2026-06-05", monto: 4200, progreso: 12, statuspago: "PAGADO", moneda: "USD" }, // Proyecto 2 — CC MONTERREY PRESA { id: 401, proyectoid: 2, clave: "02-0201", desc: "Varillas acero corrugado 3/8", inicio: "2026-04-01", fin: "2026-05-15", monto: 102000, progreso: 85, statuspago: "PAGADO" }, { id: 402, proyectoid: 2, clave: "01-0101", desc: "Fletes de maquinaria — arranque", inicio: "2026-04-19", fin: "2026-06-02", monto: 48000, progreso: 25, statuspago: "PENDIENTE" }, { id: 403, proyectoid: 2, clave: "04-0201", desc: "Motoniveladora Cat 140G", inicio: "2026-05-01", fin: "2026-07-10", monto: 18650, progreso: 0, statuspago: "PENDIENTE" }, // Proyecto 24 — OFICINA CENTRAL { id: 501, proyectoid: 24, clave: "07-0102", desc: "Papelería", inicio: "2026-04-01", fin: "2026-06-30", monto: 15000, progreso: 35, statuspago: "PAGADO" }, { id: 502, proyectoid: 24, clave: "06-0101", desc: "Impuestos Federales (SAT)", inicio: "2026-04-14", fin: "2026-06-20", monto: 12800, progreso: 50, statuspago: "PAGO_PARCIAL" } ]; // Alertas modulares ligadas a un proyecto + tarea/clave + fecha (renderizadas como pins en Gantt) const PROJECT_ALERTS_INIT = [ { id: 1, proyectoid: 27, tareaid: 102, clave: "02-0201", fecha: "2026-04-26", severidad: "alert", titulo: "Riesgo de excedente en materiales", desc: "Varillas al 96% de la asignación · revisar antes del cierre.", autor: "Mariana Vega", creada: "Hoy 09:14" }, { id: 2, proyectoid: 27, tareaid: 103, clave: "03-0101", fecha: "2026-05-08", severidad: "warn", titulo: "Nómina — llegada parcial", desc: "Solo se ha procesado el 45% de la nómina. Pendiente liquidación.", autor: "Carlos Ortega", creada: "Hoy 11:30" }, { id: 3, proyectoid: 2, tareaid: 401, clave: "02-0201", fecha: "2026-05-04", severidad: "over", titulo: "OC excede ramo de materiales", desc: "Varillas PVC superaron el ramo asignado a Presa.", autor: "Mariana Vega", creada: "Ayer 18:40" }, { id: 4, proyectoid: 28, tareaid: 202, clave: "02-0402", fecha: "2026-05-05", severidad: "warn", titulo: "Geotextil — entrega pendiente", desc: "Asegurar recepción de geotextil antes del inicio de greens.", autor: "Daniel Sosa", creada: "Hace 2 días" } ]; // ───────────────────────── FAMILIAS (catalogo_insumos.codigofamilia) ───────────────────────── // Refleja los códigos y nombres reales de la BD y los presupuestos de la tabla presupuestos (anio=2026) const FAMILIAS = [ { codigo: "01", nombre: "Movilización", budget: 500000, spent: 502400, trend: [40,55,62,70,82,95,104] }, { codigo: "02", nombre: "Materiales", budget: 800000, spent: 620000, trend: [20,28,40,55,68,82,96] }, { codigo: "03", nombre: "Mano de obra", budget: 600000, spent: 332000, trend: [35,48,55,62,70,80,92] }, { codigo: "04", nombre: "Maquinaria y equipo", budget: 700000, spent: 458600, trend: [25,38,45,55,64,72,85] }, { codigo: "05", nombre: "Marketing", budget: 80000, spent: 28400, trend: [12,18,25,32,42,52,62] }, { codigo: "06", nombre: "Impuestos", budget: 120000, spent: 84000, trend: [8,15,22,28,34,42,47] }, { codigo: "07", nombre: "Administrativos", budget: 150000, spent: 112000, trend: [18,28,38,48,58,70,80] }, // 08 la creó Contraloría el 2026-07-10 y esta lista se quedó en 7: por eso // "Admin. de Proyecto" no ofrecía la familia 8, Insumos no se podía filtrar // por ella y nombreFamilia('08') devolvía "—". El desplegable de Admin. de // Proyecto ya no usa esta constante (pide las familias a la BD, ver // ClavesModal en rg-proyecciones.jsx), pero el resto de las vistas sí. { codigo: "08", nombre: "Recursos humanos", budget: 0, spent: 0, trend: [0,0,0,0,0,0,0] }, { codigo: "09", nombre: "Cajas chicas", budget: 0, spent: 0, trend: [0,0,0,0,0,0,0] } ]; // Paleta de colores para los chips de familia (9 colores, uno por código) const FAMILY_COLORS = ["#1a4d2e","#2d6a44","#4a8a63","#a88838","#c9a961","#c8651b","#1976d2","#8a5a2b","#5a6b7a"]; // Backwards-compatible alias used by older components const CATEGORIES_BASE = FAMILIAS.map(f => ({ id: f.codigo, name: f.nombre, meta: "—", budget: f.budget, spent: f.spent, trend: f.trend })); // ───────────────────────── PROVEEDORES (proveedores) ───────────────────────── // Muestra 8 proveedores representativos. Los IDs reales de la BD son distintos (180, 288, 341...) // pero para el mock se usan 1-8 para coincidir con ORDENES.proveedorid const PROVEEDORES = [ { id: 1, nombre: "Proveedor Materiales Chihuahua", rfc: "PMC990412L23", banco: "BBVA", moneda: "MXN", contacto: "Luis Pacheco", email: "ventas@pmc.mx", activo: 1, ocs: 9, monto: 84173 }, { id: 2, nombre: "Contratista Obra Civil Presa", rfc: "COC050818H44", banco: "Banamex", moneda: "MXN", contacto: "Randal Gómez", email: "contacto@cocpresa.mx", activo: 1, ocs: 2, monto: 177388 }, { id: 3, nombre: "Servicios Generales Chihuahua", rfc: "SGC070220A11", banco: "Santander", moneda: "MXN", contacto: "Beatriz Flores", email: "ventas@sgc.mx", activo: 1, ocs: 3, monto: 22958 }, { id: 4, nombre: "DIMANOR SA de CV", rfc: "DIM110630T55", banco: "Banorte", moneda: "USD", contacto: "Daniel Castelandelamancha", email: "ventas01@dimanor.com", activo: 1, ocs: 8, monto: 50776 }, { id: 5, nombre: "Constructora Hermosillo Norte", rfc: "CHN960115F77", banco: "BBVA", moneda: "MXN", contacto: "Gerardo López", email: "info@chn.mx", activo: 1, ocs: 2, monto: 208800 }, { id: 6, nombre: "Proveedor Maquinaria Chihuahua", rfc: "PMQ020410B22", banco: "Banorte", moneda: "MXN", contacto: "Erick Macías", email: "pmq@proveedores.mx", activo: 1, ocs: 2, monto: 4872 }, { id: 7, nombre: "Constructora Materiales Riberas", rfc: "CMR080912R33", banco: "HSBC", moneda: "MXN", contacto: "Randal Gómez", email: "cmr@riberas.mx", activo: 1, ocs: 1, monto: 120060 }, { id: 8, nombre: "Proveedor USD Las Riberas", rfc: "FOREIGN", banco: "Wells Fargo", moneda: "USD", contacto: "Karen Smith", email: "sales@lasriberas.com", activo: 0, ocs: 1, monto: 20175 } ]; // ───────────────────────── ÓRDENES DE COMPRA (ordenes_compra + oc_partidas) ───────────────────────── // statuspago: PAGADO | PAGO_PARCIAL | PENDIENTE // statusflujo: NUEVO | CON_PRIORIDAD | AUTORIZADA ← enum real de la BD // prioridad: NORMAL | URGENTE | CRITICO | AUTORIZADO const ORDENES = [ { id: 1, folio: 0, fecha: "2026-04-28", proyectoid: 27, proveedorid: 1, moneda: "MXN", subtotal: 12218, iva: 1954, total: 14173, statuspago: "PAGADO", montopagado: 14173, montopendiente: 0, prioridad: "NORMAL", statusflujo: "NUEVO", familia: "01" }, { id: 2, folio: 1, fecha: "2026-04-28", proyectoid: 2, proveedorid: 2, moneda: "MXN", subtotal: 152921, iva: 24467, total: 177388, statuspago: "PENDIENTE", montopagado: 0, montopendiente: 177388, prioridad: "NORMAL", statusflujo: "NUEVO", familia: "02" }, { id: 3, folio: 2, fecha: "2026-04-28", proyectoid: 27, proveedorid: 3, moneda: "MXN", subtotal: 5000, iva: 800, total: 5800, statuspago: "PENDIENTE", montopagado: 0, montopendiente: 5800, prioridad: "NORMAL", statusflujo: "NUEVO", familia: "03" }, { id: 4, folio: 3, fecha: "2026-04-28", proyectoid: 27, proveedorid: 4, moneda: "USD", subtotal: 732, iva: 117, total: 850, statuspago: "PAGADO", montopagado: 850, montopendiente: 0, prioridad: "NORMAL", statusflujo: "NUEVO", familia: "04" }, { id: 5, folio: 4, fecha: "2026-04-28", proyectoid: 27, proveedorid: 4, moneda: "USD", subtotal: 11951, iva: 1912, total: 13863, statuspago: "PAGADO", montopagado: 13863, montopendiente: 0, prioridad: "NORMAL", statusflujo: "NUEVO", familia: "02" }, { id: 6, folio: 5, fecha: "2026-04-28", proyectoid: 27, proveedorid: 4, moneda: "USD", subtotal: 11275, iva: 1804, total: 13079, statuspago: "PENDIENTE", montopagado: 0, montopendiente: 13079, prioridad: "NORMAL", statusflujo: "NUEVO", familia: "02" }, { id: 7, folio: 14, fecha: "2026-04-28", proyectoid: 28, proveedorid: 5, moneda: "MXN", subtotal: 180000, iva: 28800, total: 208800, statuspago: "PAGADO", montopagado: 208800, montopendiente: 0, prioridad: "NORMAL", statusflujo: "AUTORIZADA", familia: "02" }, { id: 8, folio: 16, fecha: "2026-04-28", proyectoid: 27, proveedorid: 6, moneda: "MXN", subtotal: 4200, iva: 672, total: 4872, statuspago: "PAGADO", montopagado: 4872, montopendiente: 0, prioridad: "CRITICO", statusflujo: "AUTORIZADA", familia: "01" }, { id: 9, folio: 23, fecha: "2026-04-29", proyectoid: 28, proveedorid: 7, moneda: "MXN", subtotal: 103500, iva: 16560, total: 120060, statuspago: "PAGADO", montopagado: 120060, montopendiente: 0, prioridad: "NORMAL", statusflujo: "NUEVO", familia: "02" }, { id: 10, folio: 24, fecha: "2026-04-29", proyectoid: 28, proveedorid: 8, moneda: "USD", subtotal: 17392, iva: 2782, total: 20175, statuspago: "PENDIENTE", montopagado: 0, montopendiente: 20175, prioridad: "NORMAL", statusflujo: "AUTORIZADA", familia: "02" }, { id: 11, folio: 25, fecha: "2026-04-29", proyectoid: 27, proveedorid: 3, moneda: "MXN", subtotal: 3629, iva: 0, total: 3629, statuspago: "PAGADO", montopagado: 3629, montopendiente: 0, prioridad: "URGENTE", statusflujo: "CON_PRIORIDAD", familia: "03" } ]; // ───────────────────────── HISTORIAL (historial) ───────────────────────── const HISTORIAL = [ { id: 1, fecha: "2026-04-28 16:19", usuario: "DANIEL CASTELAN", accion: "CREAR_OC", desc: "OC #0 creada — VALLE DE LOS ENCINOS", tabla: "ordenes_compra" }, { id: 2, fecha: "2026-04-28 17:55", usuario: "RANDAL GOMEZ", accion: "CREAR_OC", desc: "OC #1 creada — CC MONTERREY PRESA", tabla: "ordenes_compra" }, { id: 3, fecha: "2026-04-28 21:10", usuario: "RANDAL GOMEZ", accion: "CREAR_OC", desc: "OC #14 creada — LAS RIBERAS · $208,800 MXN", tabla: "ordenes_compra" }, { id: 4, fecha: "2026-04-28 21:24", usuario: "ERICK MACIAS", accion: "CAMBIO_PRIORIDAD",desc: "OC #16 marcada como CRÍTICA — VALLE LOS ENCINOS",tabla: "ordenes_compra" }, { id: 5, fecha: "2026-04-29 03:52", usuario: "CONTRALOR", accion: "EDITAR_OC", desc: "OC #16 autorizada — statusflujo → AUTORIZADA", tabla: "ordenes_compra" }, { id: 6, fecha: "2026-04-29 22:06", usuario: "CONTRALOR", accion: "EDITAR_OC", desc: "OC #14 autorizada — statusflujo → AUTORIZADA", tabla: "ordenes_compra" }, { id: 7, fecha: "2026-04-29 22:37", usuario: "RANDAL GOMEZ", accion: "PAGO_REGISTRADO", desc: "Pago $120,060 OC #23 — LAS RIBERAS", tabla: "oc_pagos" }, { id: 8, fecha: "2026-05-01 00:48", usuario: "CONTRALOR", accion: "PAGO_REGISTRADO", desc: "Pago USD 850 OC #3 — VALLE DE LOS ENCINOS", tabla: "oc_pagos" }, { id: 9, fecha: "2026-05-01 01:07", usuario: "CONTRALOR", accion: "PAGO_REGISTRADO", desc: "Pago USD 2,616 OC #6 — VALLE DE LOS ENCINOS", tabla: "oc_pagos" }, { id:10, fecha: "2026-05-04 14:26", usuario: "CONTRALOR", accion: "EDITAR_OC", desc: "OC #19 actualizada — statusflujo → AUTORIZADA", tabla: "ordenes_compra" }, { id:11, fecha: "2026-05-06 23:43", usuario: "ERICK MACIAS", accion: "PAGO_REGISTRADO", desc: "Pago $15,724 OC #29 — VALLE DE LOS ENCINOS", tabla: "oc_pagos" }, { id:12, fecha: "2026-05-08 18:16", usuario: "LUIS ANGEL", accion: "EDITAR_OC", desc: "OC #15 modificada — CC MONTERREY PRESA", tabla: "ordenes_compra" } ]; // ───────────────────────── ALERTAS DERIVADAS ───────────────────────── const ALERTS_DATA = [ { id: 1, level: "over", cat: "01", title: "Movilización excedió el presupuesto", desc: "Categoría 01 cerró en 100.5%. OC reciente superó la asignación.", time: "Hace 12 min · Auto" }, { id: 2, level: "alert", cat: "02", title: "Materiales al 77.5%", desc: "Cruzó el umbral del 70%. Revisar OCs pendientes antes de generar nuevas.", time: "Hace 1 h · Auto" }, { id: 3, level: "alert", cat: "03", title: "Mano de obra al 55%", desc: "Proyección de cierre superior al 90% a fin de año al ritmo actual.", time: "Hoy 09:14 · Auto" }, { id: 4, level: "warn", cat: "07", title: "Administrativos al 75%", desc: "Llegó al primer umbral. Hay partidas de papelería pendientes de recibir.", time: "Hoy 08:02 · Auto" }, { id: 5, level: "warn", cat: "04", title: "Maquinaria y equipo al 65%", desc: "Crecimiento +18% vs mes anterior. Rentas de equipo pendientes de autorizar.", time: "Ayer 18:40 · Auto" }, { id: 6, level: "ok", cat: "05", title: "Marketing dentro de presupuesto", desc: "Cerró en 35%. Sin acciones requeridas.", time: "Ayer 14:20 · Auto" } ]; // Recent OCs alias for old dashboard const RECENT_OCS = ORDENES.slice(0, 5).map(o => { const prov = PROVEEDORES.find(p => p.id === o.proveedorid) || { nombre: "—" }; return { folio: "OC-" + o.folio, vendor: prov.nombre, cat: o.familia, amount: o.total, status: o.statuspago === "PAGADO" ? "approved" : "pending" }; }); // ───────────────────────── HELPERS ───────────────────────── function flagLevel(pct, t = DEFAULT_THRESHOLDS) { if (pct >= t.over) return "over"; if (pct >= t.alert) return "alert"; if (pct >= t.warn) return "warn"; return "ok"; } function fmtMoney(n, opts = {}) { const { compact, sign } = opts; if (compact && Math.abs(n) >= 1000) { const k = n / 1000; return (k >= 1000 ? (k/1000).toFixed(1)+"M" : k.toFixed(0)+"K"); } const s = Math.round(n).toLocaleString("es-MX"); return sign && n > 0 ? "+" + s : s; } function flagColor(level) { return ({ ok: "var(--rg-flag-ok)", warn: "var(--rg-flag-warn)", alert: "var(--rg-flag-alert)", over: "var(--rg-flag-over)" })[level]; } function levelLabel(level) { return { ok: "OK", warn: "AVISO 80%", alert: "ALERTA 90%", over: "EXCEDIDO" }[level]; } function fmtFolio(f) { return "OC-" + String(f).slice(0,4) + "-" + String(f).slice(4); } function fmtFecha(d) { const [y,m,dd] = d.split("-"); return `${dd}/${m}/${y.slice(2)}`; } function nombreProyecto(id) { return (PROYECTOS.find(p => p.id === id) || {}).nombre || "—"; } function nombreProveedor(id) { return (PROVEEDORES.find(p => p.id === id) || {}).nombre || "—"; } function nombreFamilia(cod) { return (FAMILIAS.find(f => f.codigo === cod) || {}).nombre || "—"; } // ───────────────────────── ICONS ───────────────────────── const Icon = { dashboard: (s = 16) => (), budget: (s = 16) => (), oc: (s = 16) => (), vendors: (s = 16) => (), catalog: (s = 16) => (), history: (s = 16) => (), bell: (s = 16) => (), settings: (s = 16) => (), reports: (s = 16) => (), search: (s = 14) => (), filter: (s = 14) => (), download: (s = 14) => (), more: (s = 14) => (), arrowRight: (s = 12) => (), arrowUp: (s = 12) => (), arrowDown: (s = 12) => (), check: (s = 12) => (), x: (s = 12) => (), plus: (s = 14) => (), edit: (s = 14) => (), eye: (s = 14) => (), excel: (s = 14) => (), reporteia: (s = 16) => (), info: (s = 14) => () }; // Ícono de ayuda con tooltip nativo (title) — para explicar en una frase corta // un dato que puede confundirse con otro parecido (ej. "Ejercido" vs "Costo // Acumulado", que a propósito cuentan cosas distintas). No es un tooltip rico, // solo el title del navegador — consistente con el resto de la app. function HelpHint({ text, style }) { return ( {Icon.info(13)} ); } // Barra en dos tramos sobre el presupuesto: verde lo PAGADO, amarillo lo que // falta por pagar de las OCs vivas. Si lo comprometido supera el presupuesto, todo // el excedente se pinta en rojo, igual que antes. function BarraPresupuesto({ monto, pagado, porPagar }) { const base = Number(monto) || 0; const pag = Math.max(0, Number(pagado) || 0); const pend = Math.max(0, Number(porPagar) || 0); const comp = pag + pend; const excedido = base > 0 && comp > base; // Con el presupuesto excedido la escala es el comprometido, para que se vea // cuanto de lo gastado ya no cabe. const escala = excedido ? comp : (base || 1); const wPag = Math.min(100, (pag / escala) * 100); const wPend = Math.min(100 - wPag, (pend / escala) * 100); return (