no se que modificaciones se hizo posible error

This commit is contained in:
unknown
2026-06-13 12:04:04 -04:00
parent ff90340fdb
commit fa05ae3754
24 changed files with 2466 additions and 402 deletions

View File

@@ -0,0 +1,272 @@
import { db } from '../db.js';
const LEGACY_KEY = 'fecha_cierre_gestion';
export function todayStr() {
return new Date().toISOString().slice(0, 10);
}
function addDays(isoDate, days) {
const d = new Date(isoDate + 'T12:00:00');
d.setDate(d.getDate() + days);
return d.toISOString().slice(0, 10);
}
function etiquetaFromRange(inicio, fin) {
const ref = fin || inicio;
const [y, m] = ref.split('-');
const meses = [
'Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio',
'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre',
];
return `${meses[Number(m) - 1]} ${y}`;
}
function mapGestion(row) {
if (!row) return null;
return {
id: row.id,
etiqueta: row.etiqueta,
fechaInicio: row.fecha_inicio,
fechaFin: row.fecha_fin,
esActual: row.fecha_fin === null,
cerradaAt: row.cerrada_at,
};
}
export function ensureGestionesMigrated() {
const count = db.prepare('SELECT COUNT(*) AS n FROM gestiones').get().n;
if (count > 0) return;
const legacy = db.prepare('SELECT value FROM settings WHERE key = ?').get(LEGACY_KEY);
if (legacy?.value) {
const fin = legacy.value;
const inicio = `${fin.slice(0, 7)}-01`;
db.prepare(
`INSERT INTO gestiones (etiqueta, fecha_inicio, fecha_fin, cerrada_at)
VALUES (?, ?, ?, datetime('now'))`
).run(etiquetaFromRange(inicio, fin), inicio, fin);
const nuevoInicio = addDays(fin, 1);
db.prepare(
`INSERT INTO gestiones (etiqueta, fecha_inicio, fecha_fin) VALUES (?, ?, NULL)`
).run('Gestión actual', nuevoInicio);
db.prepare(`DELETE FROM settings WHERE key = ?`).run(LEGACY_KEY);
return;
}
db.prepare(
`INSERT INTO gestiones (etiqueta, fecha_inicio, fecha_fin) VALUES ('Gestión actual', '2020-01-01', NULL)`
).run();
}
export function listGestiones() {
ensureGestionesMigrated();
return db
.prepare('SELECT * FROM gestiones ORDER BY fecha_inicio DESC')
.all()
.map(mapGestion);
}
export function getGestionActual() {
ensureGestionesMigrated();
const row = db
.prepare('SELECT * FROM gestiones WHERE fecha_fin IS NULL ORDER BY id DESC LIMIT 1')
.get();
return mapGestion(row);
}
export function getGestionById(id) {
ensureGestionesMigrated();
const row = db.prepare('SELECT * FROM gestiones WHERE id = ?').get(id);
return mapGestion(row);
}
export function findGestionForFecha(fecha) {
if (!fecha || String(fecha).trim() === '') return getGestionActual();
const f = String(fecha).slice(0, 10);
const row = db
.prepare(
`SELECT * FROM gestiones
WHERE fecha_inicio <= ? AND (fecha_fin IS NULL OR fecha_fin >= ?)
ORDER BY id DESC LIMIT 1`
)
.get(f, f);
return mapGestion(row);
}
export function rowBelongsToGestion(row, gestion, fechaField = 'fecha') {
if (!gestion) return true;
const fecha = row[fechaField];
if (!fecha || String(fecha).trim() === '') {
return gestion.esActual;
}
const f = String(fecha).slice(0, 10);
if (f < gestion.fechaInicio) return false;
if (gestion.fechaFin && f > gestion.fechaFin) return false;
return true;
}
/** Personal mensualizado: por gestion_id en el registro */
export function mensualBelongsToGestion(row, gestion) {
if (!gestion) return true;
if (gestion.esActual) {
return !row.gestionId || row.gestionId === gestion.id;
}
return row.gestionId === gestion.id;
}
export function filterRowsByGestion(rows, gestion, fechaField = 'fecha') {
if (!gestion) return rows;
return rows.filter((r) => rowBelongsToGestion(r, gestion, fechaField));
}
export function filterPersonalByGestion(mensualizados, eventuales, gestion) {
if (!gestion) return { mensualizados, eventuales };
return {
mensualizados: mensualizados.filter((r) => mensualBelongsToGestion(r, gestion)),
eventuales: eventuales.filter((r) => rowBelongsToGestion(r, gestion, 'fecha')),
};
}
export function isFechaEnPeriodoCerrado(fecha) {
const g = findGestionForFecha(fecha);
return g ? !g.esActual : false;
}
export function isCierreActivo() {
return db.prepare('SELECT COUNT(*) AS n FROM gestiones WHERE fecha_fin IS NOT NULL').get().n > 0
|| !!getGestionActual()?.fechaInicio;
}
export function getGestionStatus() {
ensureGestionesMigrated();
const actual = getGestionActual();
const historial = listGestiones().filter((g) => !g.esActual);
const ultimaCerrada = historial[0];
return {
gestionActual: actual,
historial,
fechaCierreGestion: ultimaCerrada?.fechaFin || null,
gestionCerrada: historial.length > 0,
hoy: todayStr(),
};
}
export function cerrarGestionActual(fechaFin, userId) {
ensureGestionesMigrated();
const actual = db
.prepare('SELECT * FROM gestiones WHERE fecha_fin IS NULL ORDER BY id DESC LIMIT 1')
.get();
if (!actual) throw new Error('No hay gestión actual abierta');
if (fechaFin < actual.fecha_inicio) {
throw new Error('La fecha de cierre no puede ser anterior al inicio de la gestión actual');
}
const etiqueta = etiquetaFromRange(actual.fecha_inicio, fechaFin);
db.prepare(
`UPDATE gestiones SET etiqueta = ?, fecha_fin = ?, cerrada_at = datetime('now'), cerrada_por = ?
WHERE id = ?`
).run(etiqueta, fechaFin, userId, actual.id);
const personalRows = db.prepare("SELECT id, data FROM registros WHERE sheet_type = 'personal'").all();
for (const r of personalRows) {
const data = JSON.parse(r.data);
if (data.tipo === 'mensualizado' && !data.gestionId) {
data.gestionId = actual.id;
db.prepare('UPDATE registros SET data = ? WHERE id = ?').run(JSON.stringify(data), r.id);
}
}
const nuevoInicio = addDays(fechaFin, 1);
const result = db
.prepare(
`INSERT INTO gestiones (etiqueta, fecha_inicio, fecha_fin) VALUES ('Gestión actual', ?, NULL)`
)
.run(nuevoInicio);
db.prepare(`DELETE FROM settings WHERE key = ?`).run(LEGACY_KEY);
return {
cerrada: mapGestion({ ...actual, etiqueta, fecha_fin: fechaFin }),
nueva: mapGestion({
id: result.lastInsertRowid,
etiqueta: 'Gestión actual',
fecha_inicio: nuevoInicio,
fecha_fin: null,
cerrada_at: null,
cerrada_por: null,
}),
};
}
function stripMeta(row) {
const { id, updated_at, bloqueada, gestionId: _g, ...rest } = row;
return rest;
}
export function mergeRowsForSave(existing, incoming, isAdmin, gestionActual, fechaField = 'fecha') {
const gid = gestionActual?.id;
const historial = existing.filter((r) => {
const f = r[fechaField];
if (!f || String(f).trim() === '') return false;
return !rowBelongsToGestion(r, gestionActual, fechaField);
});
let actuales;
if (isAdmin) {
actuales = (incoming || []).map((r) => ({ ...stripMeta(r), gestionId: gid }));
} else {
const locked = existing.filter(
(r) => rowBelongsToGestion(r, gestionActual, fechaField) && isFechaEnPeriodoCerrado(r[fechaField])
);
const unlockedIncoming = (incoming || []).filter((r) => !isFechaEnPeriodoCerrado(r[fechaField]));
actuales = [
...locked.map(stripMeta),
...unlockedIncoming.map((r) => ({ ...stripMeta(r), gestionId: gid })),
];
}
return [...historial.map(stripMeta), ...actuales];
}
export function mergePersonalForSave(existing, incomingMensual, incomingEventual, isAdmin, gestionActual) {
const gid = gestionActual?.id;
const existingM = existing.filter((r) => r.tipo === 'mensualizado');
const existingE = existing.filter((r) => r.tipo === 'eventual');
const historialM = existingM.filter((r) => r.gestionId && r.gestionId !== gid);
const historialE = existingE.filter((r) => !rowBelongsToGestion(r, gestionActual, 'fecha'));
let actualesM;
let actualesE;
if (isAdmin) {
actualesM = (incomingMensual || []).map((r) => ({ ...stripMeta(r), gestionId: r.gestionId || gid }));
actualesE = (incomingEventual || []).map((r) => ({ ...stripMeta(r), gestionId: gid }));
} else {
const unlockedM = (incomingMensual || []).filter((r) => !r.gestionId || r.gestionId === gid);
const lockedE = existingE.filter(
(r) => rowBelongsToGestion(r, gestionActual, 'fecha') && isFechaEnPeriodoCerrado(r.fecha)
);
const unlockedE = (incomingEventual || []).filter((r) => !isFechaEnPeriodoCerrado(r.fecha));
actualesM = unlockedM.map((r) => ({ ...stripMeta(r), gestionId: gid }));
actualesE = [
...lockedE.map(stripMeta),
...unlockedE.map((r) => ({ ...stripMeta(r), gestionId: gid })),
];
}
return {
mensualizados: [...historialM.map(stripMeta), ...actualesM],
eventuales: [...historialE.map(stripMeta), ...actualesE],
};
}
/** Etiqueta sugerida: último día del mes actual */
export function sugerirCierreMensual() {
const today = new Date();
const last = new Date(today.getFullYear(), today.getMonth() + 1, 0);
return last.toISOString().slice(0, 10);
}