refactor: enhance saldo calculation and display in registro-pontos page
- Updated the logic for calculating daily and period saldo differences to ensure accuracy by directly computing the difference between worked and expected hours. - Improved the display of saldo differences in the UI, including formatting adjustments for better readability. - Refactored the rendering logic to ensure consistent styling and user experience across the registro-pontos page.
This commit is contained in:
@@ -34,7 +34,7 @@
|
|||||||
? 'bg-red-50 border-red-200 text-red-700 dark:bg-red-900/20 dark:border-red-800 dark:text-red-400'
|
? 'bg-red-50 border-red-200 text-red-700 dark:bg-red-900/20 dark:border-red-800 dark:text-red-400'
|
||||||
: 'bg-green-50 border-green-200 text-green-700 dark:bg-green-900/20 dark:border-green-800 dark:text-green-400'
|
: 'bg-green-50 border-green-200 text-green-700 dark:bg-green-900/20 dark:border-green-800 dark:text-green-400'
|
||||||
}">
|
}">
|
||||||
<span class="font-bold">+{trabalhado.horas}h {trabalhado.minutos}min</span>
|
<span class="font-bold text-green-600 dark:text-green-400">+{trabalhado.horas}h {trabalhado.minutos}min</span>
|
||||||
<span class="text-base-content/50">/</span>
|
<span class="text-base-content/50">/</span>
|
||||||
<span class={isNegativo ? 'text-red-600 dark:text-red-400' : 'text-green-600 dark:text-green-400'}>
|
<span class={isNegativo ? 'text-red-600 dark:text-red-400' : 'text-green-600 dark:text-green-400'}>
|
||||||
{sinalDiferenca}{diferenca.horas}h {diferenca.minutos}min
|
{sinalDiferenca}{diferenca.horas}h {diferenca.minutos}min
|
||||||
|
|||||||
@@ -421,11 +421,11 @@
|
|||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
// Fallback: usar cálculo simples se não houver configuração
|
// Fallback: usar cálculo simples se não houver configuração
|
||||||
const primeiroRegistro = grupoData.registros[0];
|
const primeiroRegistro = grupoData.registros[0];
|
||||||
if (primeiroRegistro && 'saldoDiario' in primeiroRegistro && primeiroRegistro.saldoDiario) {
|
if (primeiroRegistro && 'saldoDiario' in primeiroRegistro && primeiroRegistro.saldoDiario) {
|
||||||
grupoData.saldoDiario = primeiroRegistro.saldoDiario;
|
grupoData.saldoDiario = primeiroRegistro.saldoDiario;
|
||||||
} else {
|
} else {
|
||||||
grupoData.saldoDiario = calcularSaldoDiario(grupoData.registros);
|
grupoData.saldoDiario = calcularSaldoDiario(grupoData.registros);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1496,9 +1496,12 @@
|
|||||||
saldoDiarioTotalDiferencaMinutos = -saldoDiarioTotalEsperadoMinutos; // Diferença negativa (0 - esperado)
|
saldoDiarioTotalDiferencaMinutos = -saldoDiarioTotalEsperadoMinutos; // Diferença negativa (0 - esperado)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calcular diferença corretamente: trabalhado - esperado (não somar diferenças dos pares)
|
||||||
|
const diferencaDiariaCorrigida = saldoDiarioTotalTrabalhadoMinutos - saldoDiarioTotalEsperadoMinutos;
|
||||||
|
|
||||||
// Armazenar saldo diário completo (usado no resumo do banco de horas)
|
// Armazenar saldo diário completo (usado no resumo do banco de horas)
|
||||||
saldosDiariosPorData[data] = {
|
saldosDiariosPorData[data] = {
|
||||||
diferencaMinutos: saldoDiarioTotalDiferencaMinutos,
|
diferencaMinutos: diferencaDiariaCorrigida,
|
||||||
trabalhadoMinutos: saldoDiarioTotalTrabalhadoMinutos,
|
trabalhadoMinutos: saldoDiarioTotalTrabalhadoMinutos,
|
||||||
esperadoMinutos: saldoDiarioTotalEsperadoMinutos
|
esperadoMinutos: saldoDiarioTotalEsperadoMinutos
|
||||||
};
|
};
|
||||||
@@ -1646,9 +1649,9 @@
|
|||||||
// Se não há tempo trabalhado, decrementar o tempo esperado completo
|
// Se não há tempo trabalhado, decrementar o tempo esperado completo
|
||||||
if (saldoEsperado.trabalhadoMinutos === 0) {
|
if (saldoEsperado.trabalhadoMinutos === 0) {
|
||||||
saldoDiarioAcumuladoMinutos -= saldoEsperado.esperadoMinutos;
|
saldoDiarioAcumuladoMinutos -= saldoEsperado.esperadoMinutos;
|
||||||
} else {
|
} else {
|
||||||
saldoDiarioAcumuladoMinutos -= saldoEsperado.trabalhadoMinutos;
|
saldoDiarioAcumuladoMinutos -= saldoEsperado.trabalhadoMinutos;
|
||||||
}
|
}
|
||||||
paresProcessadosParaSaldo.add(chavePar);
|
paresProcessadosParaSaldo.add(chavePar);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1664,7 +1667,7 @@
|
|||||||
// Marcar linha para aplicar cor no saldo
|
// Marcar linha para aplicar cor no saldo
|
||||||
if (trabalhouMaisQueEsperado) {
|
if (trabalhouMaisQueEsperado) {
|
||||||
linha._saldoPositivo = true; // Verde: trabalhou mais que o esperado
|
linha._saldoPositivo = true; // Verde: trabalhou mais que o esperado
|
||||||
} else {
|
} else {
|
||||||
linha._saldoNegativo = true; // Vermelho: ainda falta trabalhar
|
linha._saldoNegativo = true; // Vermelho: ainda falta trabalhar
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1756,9 +1759,9 @@
|
|||||||
content: `0h 0min parcial | Saldo: ${sinalSaldo}${saldoAcumuladoHoras}h ${saldoAcumuladoMinutosResto}min`,
|
content: `0h 0min parcial | Saldo: ${sinalSaldo}${saldoAcumuladoHoras}h ${saldoAcumuladoMinutosResto}min`,
|
||||||
rowSpan: 2 // retorno_almoco + saida
|
rowSpan: 2 // retorno_almoco + saida
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
linha.push('-');
|
linha.push('-');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Há registros reais mas este par não foi marcado completamente
|
// Há registros reais mas este par não foi marcado completamente
|
||||||
// Verificar se é um par completamente não marcado
|
// Verificar se é um par completamente não marcado
|
||||||
@@ -1921,7 +1924,6 @@
|
|||||||
const cargaHorariaDiariaEsperadaMinutos = minutosPar1EsperadoAjustadoConfig + minutosPar2EsperadoAjustadoConfig;
|
const cargaHorariaDiariaEsperadaMinutos = minutosPar1EsperadoAjustadoConfig + minutosPar2EsperadoAjustadoConfig;
|
||||||
|
|
||||||
// Calcular saldos do período selecionado baseado nos saldos diários calculados
|
// Calcular saldos do período selecionado baseado nos saldos diários calculados
|
||||||
let saldoPeriodoDiferencaMinutos = 0;
|
|
||||||
let saldoPeriodoTrabalhadoMinutos = 0;
|
let saldoPeriodoTrabalhadoMinutos = 0;
|
||||||
let diasComSaldoPositivo = 0;
|
let diasComSaldoPositivo = 0;
|
||||||
let diasComSaldoNegativo = 0;
|
let diasComSaldoNegativo = 0;
|
||||||
@@ -1930,12 +1932,14 @@
|
|||||||
if (sections.registrosPonto && Object.keys(saldosDiariosPorData).length > 0) {
|
if (sections.registrosPonto && Object.keys(saldosDiariosPorData).length > 0) {
|
||||||
// Somar todos os saldos diários do período
|
// Somar todos os saldos diários do período
|
||||||
for (const saldo of Object.values(saldosDiariosPorData)) {
|
for (const saldo of Object.values(saldosDiariosPorData)) {
|
||||||
saldoPeriodoDiferencaMinutos += saldo.diferencaMinutos;
|
|
||||||
saldoPeriodoTrabalhadoMinutos += saldo.trabalhadoMinutos;
|
saldoPeriodoTrabalhadoMinutos += saldo.trabalhadoMinutos;
|
||||||
|
|
||||||
if (saldo.diferencaMinutos > 0) {
|
// Calcular diferença diária corretamente: trabalhado - esperado
|
||||||
|
const diferencaDiaria = saldo.trabalhadoMinutos - saldo.esperadoMinutos;
|
||||||
|
|
||||||
|
if (diferencaDiaria > 0) {
|
||||||
diasComSaldoPositivo++;
|
diasComSaldoPositivo++;
|
||||||
} else if (saldo.diferencaMinutos < 0) {
|
} else if (diferencaDiaria < 0) {
|
||||||
diasComSaldoNegativo++;
|
diasComSaldoNegativo++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1962,14 +1966,21 @@
|
|||||||
for (const regs of Object.values(registrosPorDataPeriodo)) {
|
for (const regs of Object.values(registrosPorDataPeriodo)) {
|
||||||
const saldoDiario = calcularSaldoDiario(regs);
|
const saldoDiario = calcularSaldoDiario(regs);
|
||||||
if (saldoDiario) {
|
if (saldoDiario) {
|
||||||
saldoPeriodoDiferencaMinutos += saldoDiario.saldoMinutos;
|
|
||||||
saldoPeriodoTrabalhadoMinutos += saldoDiario.saldoMinutos;
|
saldoPeriodoTrabalhadoMinutos += saldoDiario.saldoMinutos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calcular saldo esperado do período: carga horária diária × número de dias
|
// Calcular saldo esperado do período: carga horária diária × número de dias
|
||||||
|
// SEMPRE calcular diretamente, não somar saldos diários esperados (pode duplicar)
|
||||||
const saldoPeriodoEsperadoMinutos = cargaHorariaDiariaEsperadaMinutos * totalDiasPeriodo;
|
const saldoPeriodoEsperadoMinutos = cargaHorariaDiariaEsperadaMinutos * totalDiasPeriodo;
|
||||||
|
|
||||||
|
// Calcular diferença do período corretamente: trabalhado - esperado (para "Saldo do Período Exibido")
|
||||||
|
const saldoPeriodoDiferencaMinutos = saldoPeriodoTrabalhadoMinutos - saldoPeriodoEsperadoMinutos;
|
||||||
|
|
||||||
|
// Calcular diferença do período (trabalhado - esperado) para exibição na linha "Diferença do Período"
|
||||||
|
// Negativo quando trabalhado < esperado (vermelho), positivo quando trabalhado > esperado (verde)
|
||||||
|
const diferencaPeriodoTrabalhadoMenosEsperado = saldoPeriodoTrabalhadoMinutos - saldoPeriodoEsperadoMinutos;
|
||||||
|
|
||||||
// Calcular médias diárias
|
// Calcular médias diárias
|
||||||
const mediaDiariaTrabalhadaHoras = totalDiasPeriodo > 0 ? Math.floor(saldoPeriodoTrabalhadoMinutos / 60 / totalDiasPeriodo) : 0;
|
const mediaDiariaTrabalhadaHoras = totalDiasPeriodo > 0 ? Math.floor(saldoPeriodoTrabalhadoMinutos / 60 / totalDiasPeriodo) : 0;
|
||||||
@@ -1994,11 +2005,19 @@
|
|||||||
const mediaDiariaEsperadaMinutos = totalEsperadoDiarioMinutos % 60;
|
const mediaDiariaEsperadaMinutos = totalEsperadoDiarioMinutos % 60;
|
||||||
|
|
||||||
// Formatar valores
|
// Formatar valores
|
||||||
|
// Saldo do Período Exibido: diferença (trabalhado - esperado)
|
||||||
const horasPeriodoDiferenca = Math.floor(Math.abs(saldoPeriodoDiferencaMinutos) / 60);
|
const horasPeriodoDiferenca = Math.floor(Math.abs(saldoPeriodoDiferencaMinutos) / 60);
|
||||||
const minutosPeriodoDiferenca = Math.abs(saldoPeriodoDiferencaMinutos) % 60;
|
const minutosPeriodoDiferenca = Math.abs(saldoPeriodoDiferencaMinutos) % 60;
|
||||||
const sinalPeriodoDiferenca = saldoPeriodoDiferencaMinutos >= 0 ? '+' : '-';
|
const sinalPeriodoDiferenca = saldoPeriodoDiferencaMinutos >= 0 ? '+' : '-';
|
||||||
const saldoPeriodoDiferencaFormatado = `${sinalPeriodoDiferenca}${horasPeriodoDiferenca}h ${minutosPeriodoDiferenca}min`;
|
const saldoPeriodoDiferencaFormatado = `${sinalPeriodoDiferenca}${horasPeriodoDiferenca}h ${minutosPeriodoDiferenca}min`;
|
||||||
|
|
||||||
|
// Diferença do Período: trabalhado - esperado
|
||||||
|
// Negativo quando trabalhado < esperado (vermelho), positivo quando trabalhado > esperado (verde)
|
||||||
|
const horasDiferencaPeriodo = Math.floor(Math.abs(diferencaPeriodoTrabalhadoMenosEsperado) / 60);
|
||||||
|
const minutosDiferencaPeriodo = Math.abs(diferencaPeriodoTrabalhadoMenosEsperado) % 60;
|
||||||
|
const sinalDiferencaPeriodo = diferencaPeriodoTrabalhadoMenosEsperado >= 0 ? '+' : '-';
|
||||||
|
const diferencaPeriodoFormatado = `${sinalDiferencaPeriodo}${horasDiferencaPeriodo}h ${minutosDiferencaPeriodo}min`;
|
||||||
|
|
||||||
const horasPeriodoTrabalhado = Math.floor(saldoPeriodoTrabalhadoMinutos / 60);
|
const horasPeriodoTrabalhado = Math.floor(saldoPeriodoTrabalhadoMinutos / 60);
|
||||||
const minutosPeriodoTrabalhado = saldoPeriodoTrabalhadoMinutos % 60;
|
const minutosPeriodoTrabalhado = saldoPeriodoTrabalhadoMinutos % 60;
|
||||||
const saldoPeriodoTrabalhadoFormatado = `+${horasPeriodoTrabalhado}h ${minutosPeriodoTrabalhado}min`;
|
const saldoPeriodoTrabalhadoFormatado = `+${horasPeriodoTrabalhado}h ${minutosPeriodoTrabalhado}min`;
|
||||||
@@ -2049,7 +2068,7 @@
|
|||||||
bancoHorasData.push(['', '']); // Linha separadora
|
bancoHorasData.push(['', '']); // Linha separadora
|
||||||
bancoHorasData.push(['Saldo Trabalhado do Período', saldoPeriodoTrabalhadoFormatado]);
|
bancoHorasData.push(['Saldo Trabalhado do Período', saldoPeriodoTrabalhadoFormatado]);
|
||||||
bancoHorasData.push(['Saldo Esperado do Período', saldoPeriodoEsperadoFormatado]);
|
bancoHorasData.push(['Saldo Esperado do Período', saldoPeriodoEsperadoFormatado]);
|
||||||
bancoHorasData.push(['Diferença do Período', saldoPeriodoDiferencaFormatado]);
|
bancoHorasData.push(['Diferença do Período', diferencaPeriodoFormatado]);
|
||||||
|
|
||||||
// Adicionar estatísticas
|
// Adicionar estatísticas
|
||||||
bancoHorasData.push(['', '']); // Linha separadora
|
bancoHorasData.push(['', '']); // Linha separadora
|
||||||
@@ -2105,11 +2124,14 @@
|
|||||||
}
|
}
|
||||||
} else if (valor.includes('+') || campo.includes('Trabalhado') || campo.includes('Esperado')) {
|
} else if (valor.includes('+') || campo.includes('Trabalhado') || campo.includes('Esperado')) {
|
||||||
// Verde para valores positivos ou campos de trabalhado/esperado
|
// Verde para valores positivos ou campos de trabalhado/esperado
|
||||||
if (campo.includes('Diferença') && saldoPeriodoDiferencaMinutos < 0) {
|
if (campo.includes('Diferença do Período')) {
|
||||||
data.cell.styles.textColor = [200, 0, 0]; // Vermelho se diferença negativa
|
// Diferença do Período: trabalhado - esperado
|
||||||
data.cell.styles.fontStyle = 'bold';
|
// Negativo quando trabalhado < esperado (vermelho), positivo quando trabalhado > esperado (verde)
|
||||||
} else if (campo.includes('Diferença') && saldoPeriodoDiferencaMinutos > 0) {
|
if (diferencaPeriodoTrabalhadoMenosEsperado < 0) {
|
||||||
data.cell.styles.textColor = [0, 128, 0]; // Verde se diferença positiva
|
data.cell.styles.textColor = [200, 0, 0]; // Vermelho quando trabalhado < esperado
|
||||||
|
} else if (diferencaPeriodoTrabalhadoMenosEsperado > 0) {
|
||||||
|
data.cell.styles.textColor = [0, 128, 0]; // Verde quando trabalhado > esperado
|
||||||
|
}
|
||||||
data.cell.styles.fontStyle = 'bold';
|
data.cell.styles.fontStyle = 'bold';
|
||||||
} else if (campo.includes('Trabalhado') || campo.includes('Esperado')) {
|
} else if (campo.includes('Trabalhado') || campo.includes('Esperado')) {
|
||||||
data.cell.styles.textColor = [0, 128, 0]; // Verde para trabalhado/esperado
|
data.cell.styles.textColor = [0, 128, 0]; // Verde para trabalhado/esperado
|
||||||
@@ -2226,6 +2248,20 @@
|
|||||||
theme: 'grid',
|
theme: 'grid',
|
||||||
headStyles: { fillColor: [41, 128, 185], fontStyle: 'bold' },
|
headStyles: { fillColor: [41, 128, 185], fontStyle: 'bold' },
|
||||||
styles: { fontSize: 9 },
|
styles: { fontSize: 9 },
|
||||||
|
columnStyles: {
|
||||||
|
0: { cellWidth: 30 }, // Data
|
||||||
|
1: { cellWidth: 40 }, // Tipo
|
||||||
|
2: { cellWidth: 50, cellPadding: { top: 2, bottom: 2, left: 2, right: 2 } }, // Detalhes - maior largura
|
||||||
|
3: { cellWidth: 40 }, // Motivo
|
||||||
|
4: { cellWidth: 'auto' }, // Observações
|
||||||
|
},
|
||||||
|
didParseCell: function(data) {
|
||||||
|
// Permitir quebra de linha na coluna Detalhes (índice 2)
|
||||||
|
if (data.column.index === 2) {
|
||||||
|
data.cell.styles.overflow = 'linebreak';
|
||||||
|
data.cell.styles.cellWidth = 50;
|
||||||
|
}
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const lastPage = doc.getNumberOfPages();
|
const lastPage = doc.getNumberOfPages();
|
||||||
@@ -2985,8 +3021,8 @@
|
|||||||
? `${distanciaExcedenteKm} km além do permitido`
|
? `${distanciaExcedenteKm} km além do permitido`
|
||||||
: `${distanciaExcedenteMetros} metros além do permitido`;
|
: `${distanciaExcedenteMetros} metros além do permitido`;
|
||||||
geofencingData.push(['Distância Excedente', excedenteTexto]);
|
geofencingData.push(['Distância Excedente', excedenteTexto]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
geofencingData.push(['Status', statusTexto]);
|
geofencingData.push(['Status', statusTexto]);
|
||||||
|
|
||||||
autoTable(doc, {
|
autoTable(doc, {
|
||||||
@@ -3759,14 +3795,14 @@
|
|||||||
<td class="whitespace-nowrap font-semibold text-sm">{dataFormatada}</td>
|
<td class="whitespace-nowrap font-semibold text-sm">{dataFormatada}</td>
|
||||||
<td class="whitespace-nowrap">
|
<td class="whitespace-nowrap">
|
||||||
<span class="badge badge-outline badge-sm font-medium text-xs">
|
<span class="badge badge-outline badge-sm font-medium text-xs">
|
||||||
{config
|
{config
|
||||||
? getTipoRegistroLabel(registro.tipo, {
|
? getTipoRegistroLabel(registro.tipo, {
|
||||||
nomeEntrada: config.nomeEntrada,
|
nomeEntrada: config.nomeEntrada,
|
||||||
nomeSaidaAlmoco: config.nomeSaidaAlmoco,
|
nomeSaidaAlmoco: config.nomeSaidaAlmoco,
|
||||||
nomeRetornoAlmoco: config.nomeRetornoAlmoco,
|
nomeRetornoAlmoco: config.nomeRetornoAlmoco,
|
||||||
nomeSaida: config.nomeSaida,
|
nomeSaida: config.nomeSaida,
|
||||||
})
|
})
|
||||||
: getTipoRegistroLabel(registro.tipo)}
|
: getTipoRegistroLabel(registro.tipo)}
|
||||||
</span>
|
</span>
|
||||||
</td>
|
</td>
|
||||||
<td class="whitespace-nowrap font-mono text-sm font-medium">{formatarHoraPonto(registro.hora, registro.minuto)}</td>
|
<td class="whitespace-nowrap font-mono text-sm font-medium">{formatarHoraPonto(registro.hora, registro.minuto)}</td>
|
||||||
@@ -3784,7 +3820,7 @@
|
|||||||
{#if grupoData.saldoDiarioComparativo}
|
{#if grupoData.saldoDiarioComparativo}
|
||||||
<SaldoDiarioComparativoBadge saldo={grupoData.saldoDiarioComparativo} size="md" />
|
<SaldoDiarioComparativoBadge saldo={grupoData.saldoDiarioComparativo} size="md" />
|
||||||
{:else if grupoData.saldoDiario}
|
{:else if grupoData.saldoDiario}
|
||||||
<SaldoDiarioBadge saldo={grupoData.saldoDiario} size="md" />
|
<SaldoDiarioBadge saldo={grupoData.saldoDiario} size="md" />
|
||||||
{:else}
|
{:else}
|
||||||
<span class="badge badge-ghost badge-lg">-</span>
|
<span class="badge badge-ghost badge-lg">-</span>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
Reference in New Issue
Block a user