@@ -923,7 +923,7 @@
diff --git a/apps/web/src/routes/(dashboard)/recursos-humanos/registro-pontos/+page.svelte b/apps/web/src/routes/(dashboard)/recursos-humanos/registro-pontos/+page.svelte
index 2e4782e..e2df0d1 100644
--- a/apps/web/src/routes/(dashboard)/recursos-humanos/registro-pontos/+page.svelte
+++ b/apps/web/src/routes/(dashboard)/recursos-humanos/registro-pontos/+page.svelte
@@ -163,6 +163,9 @@
r.dentroDoPrazo ? 'Sim' : 'Não',
]);
+ // Salvar a posição Y antes da tabela
+ const yPosAntesTabela = yPosition;
+
autoTable(doc, {
startY: yPosition,
head: [['Data', 'Tipo', 'Horário', 'Dentro do Prazo']],
@@ -172,6 +175,91 @@
styles: { fontSize: 9 },
});
+ // Obter banco de horas do funcionário
+ const bancoHoras = await client.query(api.pontos.obterBancoHorasFuncionario, {
+ funcionarioId,
+ });
+
+ // Calcular posição Y após a tabela
+ // autoTable armazena a posição final em doc.lastAutoTable.finalY
+ const lastPage = doc.getNumberOfPages();
+ doc.setPage(lastPage);
+ const finalY = (doc as any).lastAutoTable?.finalY;
+
+ // Se não conseguir obter a posição final, estimar baseado no número de linhas
+ if (finalY) {
+ yPosition = finalY;
+ } else {
+ // Estimativa: cada linha da tabela ocupa aproximadamente 7mm
+ const linhasTabela = tableData.length + 1; // +1 para o cabeçalho
+ yPosition = yPosAntesTabela + (linhasTabela * 7) + 10;
+ }
+
+ // Adicionar espaço antes do resumo
+ yPosition += 10;
+
+ // Verificar se precisa de nova página
+ if (yPosition > doc.internal.pageSize.getHeight() - 60) {
+ doc.addPage();
+ yPosition = 20;
+ }
+
+ // Resumo do Banco de Horas
+ doc.setFontSize(12);
+ doc.setFont('helvetica', 'bold');
+ doc.setTextColor(41, 128, 185);
+ doc.text('RESUMO DO BANCO DE HORAS', 15, yPosition);
+ doc.setFont('helvetica', 'normal');
+ doc.setTextColor(0, 0, 0);
+
+ yPosition += 10;
+ doc.setFontSize(10);
+
+ if (bancoHoras) {
+ const saldoMinutos = bancoHoras.saldoAcumuladoMinutos;
+ const horas = Math.floor(Math.abs(saldoMinutos) / 60);
+ const minutos = Math.abs(saldoMinutos) % 60;
+ const sinal = saldoMinutos >= 0 ? '+' : '-';
+ const saldoFormatado = `${sinal}${horas}h ${minutos}min`;
+
+ // Saldo Atual
+ doc.setFont('helvetica', 'bold');
+ doc.text('Saldo Atual:', 15, yPosition);
+ doc.setFont('helvetica', 'normal');
+ doc.text(saldoFormatado, 60, yPosition);
+ yPosition += 8;
+
+ // Horas Excedentes (se positivo)
+ if (saldoMinutos > 0) {
+ doc.setFont('helvetica', 'bold');
+ doc.setTextColor(0, 128, 0); // Verde
+ doc.text('Horas Excedentes:', 15, yPosition);
+ doc.setFont('helvetica', 'normal');
+ doc.text(`${horas}h ${minutos}min`, 75, yPosition);
+ doc.setTextColor(0, 0, 0);
+ yPosition += 8;
+ }
+
+ // Horas a Pagar (se negativo)
+ if (saldoMinutos < 0) {
+ doc.setFont('helvetica', 'bold');
+ doc.setTextColor(200, 0, 0); // Vermelho
+ doc.text('Horas a Pagar:', 15, yPosition);
+ doc.setFont('helvetica', 'normal');
+ doc.text(`${horas}h ${minutos}min`, 70, yPosition);
+ doc.setTextColor(0, 0, 0);
+ yPosition += 8;
+ }
+
+ // Total de dias registrados
+ doc.setFont('helvetica', 'bold');
+ doc.text('Total de Dias com Registro:', 15, yPosition);
+ doc.setFont('helvetica', 'normal');
+ doc.text(`${bancoHoras.totalDias} dias`, 95, yPosition);
+ } else {
+ doc.text('Banco de horas não disponível', 15, yPosition);
+ }
+
// Rodapé
const pageCount = doc.getNumberOfPages();
for (let i = 1; i <= pageCount; i++) {
diff --git a/packages/backend/convex/schema.ts b/packages/backend/convex/schema.ts
index 1a163fa..cbcc444 100644
--- a/packages/backend/convex/schema.ts
+++ b/packages/backend/convex/schema.ts
@@ -1408,6 +1408,8 @@ export default defineSchema({
nomeSaidaAlmoco: v.optional(v.string()), // Padrão: "Saída 1"
nomeRetornoAlmoco: v.optional(v.string()), // Padrão: "Entrada 2"
nomeSaida: v.optional(v.string()), // Padrão: "Saída 2"
+ // Ajuste de fuso horário (GMT offset em horas)
+ gmtOffset: v.optional(v.number()), // Padrão: 0 (UTC)
ativo: v.boolean(),
atualizadoPor: v.id("usuarios"),
atualizadoEm: v.number(),