no se que modificaciones se hizo posible error
This commit is contained in:
272
backend/src/utils/gestion.js
Normal file
272
backend/src/utils/gestion.js
Normal 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);
|
||||
}
|
||||
Reference in New Issue
Block a user