feat: implement cascading recalculation of monthly hour banks when past months are updated or adjusted

This commit is contained in:
2025-12-11 16:52:07 -03:00
parent 813d614648
commit 6936a59c21

View File

@@ -1800,7 +1800,14 @@ async function atualizarBancoHoras(
// Atualizar banco de horas mensal // Atualizar banco de horas mensal
const mes = data.substring(0, 7); // YYYY-MM const mes = data.substring(0, 7); // YYYY-MM
await calcularBancoHorasMensal(ctx, funcionarioId, mes);
// Verificar se estamos editando um mês passado
const hoje = new Date();
const mesAtual = `${hoje.getFullYear()}-${String(hoje.getMonth() + 1).padStart(2, '0')}`;
const estaEditandoMesPassado = mes < mesAtual;
// Se estamos editando um mês passado, recalcular em cascata para atualizar meses seguintes
await calcularBancoHorasMensal(ctx, funcionarioId, mes, estaEditandoMesPassado);
} }
/** /**
@@ -1918,14 +1925,74 @@ export const obterBancoHorasFuncionario = query({
} }
}); });
/**
* Recalcula meses seguintes em cascata quando um mês anterior é atualizado
* Isso garante que os saldos iniciais dos meses seguintes sejam atualizados corretamente
*/
async function recalcularMesesSeguintes(
ctx: MutationCtx,
funcionarioId: Id<'funcionarios'>,
mesAtualizado: string // YYYY-MM do mês que foi atualizado
): Promise<void> {
const hoje = new Date();
const mesAtual = `${hoje.getFullYear()}-${String(hoje.getMonth() + 1).padStart(2, '0')}`;
// Se o mês atualizado já é o mês atual ou futuro, não precisa recalcular nada
if (mesAtualizado >= mesAtual) {
return;
}
// Recalcular todos os meses do mês seguinte ao atualizado até o mês atual
// Calcular primeiro mês a recalcular (mês seguinte ao atualizado)
const [anoAtualizado, mesNumAtualizado] = mesAtualizado.split('-').map(Number);
let anoIter = anoAtualizado;
let mesNumIter = mesNumAtualizado + 1;
if (mesNumIter > 12) {
mesNumIter = 1;
anoIter += 1;
}
// Continuar enquanto o mês iterado for menor ou igual ao mês atual
while (true) {
const mesIterStr = `${anoIter}-${String(mesNumIter).padStart(2, '0')}`;
// Se passou do mês atual, parar
if (mesIterStr > mesAtual) {
break;
}
// Verificar se existe registro mensal para este mês
const bancoMensalExistente = await ctx.db
.query('bancoHorasMensal')
.withIndex('by_funcionario_mes', (q) =>
q.eq('funcionarioId', funcionarioId).eq('mes', mesIterStr)
)
.first();
// Se existe registro, recalcular (o saldo inicial mudou porque o mês anterior mudou)
if (bancoMensalExistente) {
await calcularBancoHorasMensal(ctx, funcionarioId, mesIterStr, false); // false = não recalcular cascata novamente
}
// Avançar para o próximo mês
mesNumIter += 1;
if (mesNumIter > 12) {
mesNumIter = 1;
anoIter += 1;
}
}
}
/** /**
* Calcula e atualiza banco de horas mensal para um funcionário * Calcula e atualiza banco de horas mensal para um funcionário
* Esta função deve ser chamada após atualizações no banco de horas diário * Esta função deve ser chamada após atualizações no banco de horas diário
* @param recalcularCascata - Se true, recalcula automaticamente os meses seguintes (padrão: true)
*/ */
async function calcularBancoHorasMensal( async function calcularBancoHorasMensal(
ctx: MutationCtx, ctx: MutationCtx,
funcionarioId: Id<'funcionarios'>, funcionarioId: Id<'funcionarios'>,
mes: string // YYYY-MM mes: string, // YYYY-MM
recalcularCascata: boolean = true // Por padrão, recalcula em cascata
): Promise<void> { ): Promise<void> {
// Buscar todos os bancoHoras do mês // Buscar todos os bancoHoras do mês
const dataInicio = `${mes}-01`; const dataInicio = `${mes}-01`;
@@ -2045,6 +2112,11 @@ async function calcularBancoHorasMensal(
atualizadoEm: agora atualizadoEm: agora
}); });
} }
// Recalcular meses seguintes em cascata se solicitado
if (recalcularCascata) {
await recalcularMesesSeguintes(ctx, funcionarioId, mes);
}
} }
/** /**
@@ -2534,7 +2606,14 @@ export const ajustarBancoHoras = mutation({
// Recalcular banco de horas mensal após ajuste // Recalcular banco de horas mensal após ajuste
const mes = hoje.substring(0, 7); // YYYY-MM const mes = hoje.substring(0, 7); // YYYY-MM
await calcularBancoHorasMensal(ctx, args.funcionarioId, mes);
// Verificar se estamos ajustando um mês passado
const hojeDate = new Date();
const mesAtual = `${hojeDate.getFullYear()}-${String(hojeDate.getMonth() + 1).padStart(2, '0')}`;
const estaAjustandoMesPassado = mes < mesAtual;
// Se estamos ajustando um mês passado, recalcular em cascata para atualizar meses seguintes
await calcularBancoHorasMensal(ctx, args.funcionarioId, mes, estaAjustandoMesPassado);
// Criar registro de homologação (mantido para compatibilidade) // Criar registro de homologação (mantido para compatibilidade)
const homologacaoId = await ctx.db.insert('homologacoesPonto', { const homologacaoId = await ctx.db.insert('homologacoesPonto', {
@@ -3727,7 +3806,14 @@ export const criarAjusteBancoHoras = mutation({
// Recalcular banco de horas mensal // Recalcular banco de horas mensal
const mes = args.dataAplicacao.substring(0, 7); const mes = args.dataAplicacao.substring(0, 7);
await calcularBancoHorasMensal(ctx, args.funcionarioId, mes);
// Verificar se estamos aplicando ajuste em um mês passado
const hoje = new Date();
const mesAtual = `${hoje.getFullYear()}-${String(hoje.getMonth() + 1).padStart(2, '0')}`;
const estaAplicandoEmMesPassado = mes < mesAtual;
// Se estamos aplicando em um mês passado, recalcular em cascata para atualizar meses seguintes
await calcularBancoHorasMensal(ctx, args.funcionarioId, mes, estaAplicandoEmMesPassado);
return { ajusteId, success: true }; return { ajusteId, success: true };
} }