feat: update ESLint and TypeScript configurations across frontend and backend; enhance component structure and improve data handling in various modules

This commit is contained in:
2025-12-02 16:36:02 -03:00
parent f48d28067c
commit d79e6959c3
215 changed files with 29474 additions and 28173 deletions

View File

@@ -9,12 +9,7 @@ import { validarLocalizacaoGeofencingInternal } from './enderecosMarcacao';
* Calcula distância entre duas coordenadas (fórmula de Haversine)
* Retorna distância em metros
*/
function calcularDistancia(
lat1: number,
lon1: number,
lat2: number,
lon2: number
): number {
function calcularDistancia(lat1: number, lon1: number, lat2: number, lon2: number): number {
const R = 6371000; // Raio da Terra em metros
const dLat = ((lat2 - lat1) * Math.PI) / 180;
const dLon = ((lon2 - lon1) * Math.PI) / 180;
@@ -127,12 +122,7 @@ async function validarLocalizacao(
if (ipAddress) {
const ipGeo = await obterGeoPorIP(ipAddress);
if (ipGeo) {
distanciaIPvsGPS = calcularDistancia(
latitude,
longitude,
ipGeo.latitude,
ipGeo.longitude
);
distanciaIPvsGPS = calcularDistancia(latitude, longitude, ipGeo.latitude, ipGeo.longitude);
// Se diferença > 50km, muito suspeito
if (distanciaIPvsGPS > 50000) {
@@ -176,7 +166,7 @@ async function validarLocalizacao(
// Calcular velocidade (km/h) se tempo decorrido > 0
if (tempoDecorridoHoras > 0 && tempoDecorridoHoras < 24) {
velocidadeUltimoRegistro = (distanciaUltimoRegistro / 1000) / tempoDecorridoHoras; // km/h
velocidadeUltimoRegistro = distanciaUltimoRegistro / 1000 / tempoDecorridoHoras; // km/h
// Se velocidade > 1000 km/h, impossível (mais rápido que avião)
if (velocidadeUltimoRegistro > 1000) {
@@ -280,19 +270,34 @@ function validarAcelerometro(
// Se há dados de acelerômetro, validar
if (acelerometroX !== undefined && acelerometroY !== undefined && acelerometroZ !== undefined) {
// Verificar se valores são realistas (aceleração geralmente entre -20 e +20 m/s² em uso normal)
const magnitude = magnitudeMovimento || Math.sqrt(acelerometroX * acelerometroX + acelerometroY * acelerometroY + acelerometroZ * acelerometroZ);
const magnitude =
magnitudeMovimento ||
Math.sqrt(
acelerometroX * acelerometroX +
acelerometroY * acelerometroY +
acelerometroZ * acelerometroZ
);
if (magnitude > 50) {
// Aceleração muito alta pode indicar leitura errada ou emulador
scoreConfianca *= 0.6;
avisos.push(`Magnitude de movimento muito alta (${magnitude.toFixed(2)} m/s²). Pode indicar leitura incorreta.`);
avisos.push(
`Magnitude de movimento muito alta (${magnitude.toFixed(2)} m/s²). Pode indicar leitura incorreta.`
);
}
// Se não há movimento detectado quando deveria haver (em móvel), pode ser suspeito
if (isDesktop !== true && movimentoDetectado === false && variacaoAcelerometro !== undefined && variacaoAcelerometro < 0.001) {
if (
isDesktop !== true &&
movimentoDetectado === false &&
variacaoAcelerometro !== undefined &&
variacaoAcelerometro < 0.001
) {
// Variância muito baixa pode indicar que o dispositivo está parado ou emulador
scoreConfianca *= 0.9;
avisos.push('Nenhum movimento detectado durante o registro. Pode ser normal se o dispositivo estava parado.');
avisos.push(
'Nenhum movimento detectado durante o registro. Pode ser normal se o dispositivo estava parado.'
);
}
// Se há movimento, aumenta confiança
@@ -320,7 +325,7 @@ export const generateUploadUrl = mutation({
throw new Error('Usuário não autenticado');
}
return await ctx.storage.generateUploadUrl();
},
}
});
/**
@@ -434,21 +439,21 @@ export const registrarPonto = mutation({
movimentoDetectado: v.boolean(),
magnitude: v.number(),
variacao: v.number(),
timestamp: v.number(),
timestamp: v.number()
})
),
giroscopio: v.optional(
v.object({
alpha: v.number(),
beta: v.number(),
gamma: v.number(),
gamma: v.number()
})
),
)
})
),
timestamp: v.number(),
sincronizadoComServidor: v.boolean(),
justificativa: v.optional(v.string()),
justificativa: v.optional(v.string())
},
handler: async (ctx, args) => {
const usuario = await getCurrentUserFunction(ctx);
@@ -487,7 +492,7 @@ export const registrarPonto = mutation({
const hora = dataObj.getUTCHours();
const minuto = dataObj.getUTCMinutes();
const segundo = dataObj.getUTCSeconds();
// Obter data no formato YYYY-MM-DD usando UTC
const ano = dataObj.getUTCFullYear();
const mes = String(dataObj.getUTCMonth() + 1).padStart(2, '0');
@@ -498,12 +503,12 @@ export const registrarPonto = mutation({
const funcionarioId = usuario.funcionarioId; // Já verificado acima, não é undefined
const registrosMinuto = await ctx.db
.query('registrosPonto')
.withIndex('by_funcionario_data', (q) => q.eq('funcionarioId', funcionarioId).eq('data', data))
.withIndex('by_funcionario_data', (q) =>
q.eq('funcionarioId', funcionarioId).eq('data', data)
)
.collect();
const registroDuplicado = registrosMinuto.find(
(r) => r.hora === hora && r.minuto === minuto
);
const registroDuplicado = registrosMinuto.find((r) => r.hora === hora && r.minuto === minuto);
if (registroDuplicado) {
throw new Error('Já existe um registro neste minuto');
@@ -553,7 +558,7 @@ export const registrarPonto = mutation({
if (agora.getTime() > dataFimTimestamp && !dispensa.isento) {
// Desativar dispensa expirada (mutation pode fazer isso)
await ctx.db.patch(dispensa._id, {
ativo: false,
ativo: false
});
}
}
@@ -578,7 +583,12 @@ export const registrarPonto = mutation({
break;
}
const dentroDoPrazo = calcularStatusPonto(hora, minuto, horarioConfigurado, config.toleranciaMinutos);
const dentroDoPrazo = calcularStatusPonto(
hora,
minuto,
horarioConfigurado,
config.toleranciaMinutos
);
// Validar localização se fornecida e salvar informações detalhadas
let validacaoLocalizacao: {
@@ -592,10 +602,7 @@ export const registrarPonto = mutation({
tempoDecorridoHoras?: number;
} | null = null;
if (
args.informacoesDispositivo?.latitude &&
args.informacoesDispositivo?.longitude
) {
if (args.informacoesDispositivo?.latitude && args.informacoesDispositivo?.longitude) {
validacaoLocalizacao = await validarLocalizacao(
ctx,
usuario.funcionarioId,
@@ -612,16 +619,19 @@ export const registrarPonto = mutation({
const baixaConfianca = validacaoLocalizacao.scoreConfianca < 0.5;
if (suspeitaFrontend || suspeitaBackend || baixaConfianca) {
console.warn('⚠️ LOCALIZAÇÃO COM BAIXA CONFIABILIDADE DETECTADA (registrando normalmente):', {
funcionarioId: usuario.funcionarioId,
latitude: args.informacoesDispositivo.latitude,
longitude: args.informacoesDispositivo.longitude,
confiabilidadeGPSFrontend: args.informacoesDispositivo.confiabilidadeGPS,
scoreConfiancaBackend: validacaoLocalizacao.scoreConfianca,
suspeitaFrontend: suspeitaFrontend ? args.informacoesDispositivo.motivoSuspeita : null,
suspeitaBackend: suspeitaBackend ? validacaoLocalizacao.motivo : null,
avisos: validacaoLocalizacao.avisos
});
console.warn(
'⚠️ LOCALIZAÇÃO COM BAIXA CONFIABILIDADE DETECTADA (registrando normalmente):',
{
funcionarioId: usuario.funcionarioId,
latitude: args.informacoesDispositivo.latitude,
longitude: args.informacoesDispositivo.longitude,
confiabilidadeGPSFrontend: args.informacoesDispositivo.confiabilidadeGPS,
scoreConfiancaBackend: validacaoLocalizacao.scoreConfianca,
suspeitaFrontend: suspeitaFrontend ? args.informacoesDispositivo.motivoSuspeita : null,
suspeitaBackend: suspeitaBackend ? validacaoLocalizacao.motivo : null,
avisos: validacaoLocalizacao.avisos
}
);
}
}
@@ -656,17 +666,14 @@ export const registrarPonto = mutation({
validacaoLocalizacao = {
valida: true,
scoreConfianca: 1,
avisos: [],
avisos: []
};
}
validacaoLocalizacao.avisos.push(...geofencing.avisos);
// Reduzir score de confiança se estiver fora do raio
if (!geofencing.dentroRaio) {
validacaoLocalizacao.scoreConfianca = Math.min(
validacaoLocalizacao.scoreConfianca,
0.7
);
validacaoLocalizacao.scoreConfianca = Math.min(validacaoLocalizacao.scoreConfianca, 0.7);
}
}
}
@@ -697,7 +704,8 @@ export const registrarPonto = mutation({
let scoreFinalConfianca = 1.0;
if (validacaoLocalizacao && validacaoAcelerometro) {
// GPS tem peso 0.7, acelerômetro tem peso 0.3
scoreFinalConfianca = (validacaoLocalizacao.scoreConfianca * 0.7) + (validacaoAcelerometro.scoreConfianca * 0.3);
scoreFinalConfianca =
validacaoLocalizacao.scoreConfianca * 0.7 + validacaoAcelerometro.scoreConfianca * 0.3;
} else if (validacaoLocalizacao) {
scoreFinalConfianca = validacaoLocalizacao.scoreConfianca;
} else if (validacaoAcelerometro) {
@@ -738,8 +746,19 @@ export const registrarPonto = mutation({
speed: args.informacoesDispositivo?.speed,
confiabilidadeGPS: args.informacoesDispositivo?.confiabilidadeGPS,
scoreConfiancaBackend: scoreFinalConfianca,
suspeitaSpoofing: args.informacoesDispositivo?.suspeitaSpoofing || (validacaoLocalizacao ? validacaoLocalizacao.scoreConfianca < 0.5 || !validacaoLocalizacao.valida : undefined) || (validacaoAcelerometro ? validacaoAcelerometro.scoreConfianca < 0.5 || !validacaoAcelerometro.valida : undefined),
motivoSuspeita: args.informacoesDispositivo?.motivoSuspeita || validacaoLocalizacao?.motivo || validacaoAcelerometro?.motivo || (todosAvisos.length > 0 ? todosAvisos.join('; ') : undefined),
suspeitaSpoofing:
args.informacoesDispositivo?.suspeitaSpoofing ||
(validacaoLocalizacao
? validacaoLocalizacao.scoreConfianca < 0.5 || !validacaoLocalizacao.valida
: undefined) ||
(validacaoAcelerometro
? validacaoAcelerometro.scoreConfianca < 0.5 || !validacaoAcelerometro.valida
: undefined),
motivoSuspeita:
args.informacoesDispositivo?.motivoSuspeita ||
validacaoLocalizacao?.motivo ||
validacaoAcelerometro?.motivo ||
(todosAvisos.length > 0 ? todosAvisos.join('; ') : undefined),
// Informações detalhadas de validação (sempre salvar quando houver validação)
avisosValidacao: todosAvisos.length > 0 ? todosAvisos : undefined,
// Informações de Geofencing
@@ -775,14 +794,14 @@ export const registrarPonto = mutation({
giroscopioGamma: args.informacoesDispositivo?.giroscopio?.gamma,
sensorDisponivel: args.informacoesDispositivo?.sensorDisponivel,
permissaoSensorNegada: args.informacoesDispositivo?.permissaoNegada,
criadoEm: Date.now(),
criadoEm: Date.now()
});
// Atualizar banco de horas após registrar
await atualizarBancoHoras(ctx, usuario.funcionarioId, data, config);
return { registroId, tipo, dentroDoPrazo };
},
}
});
/**
@@ -791,7 +810,7 @@ export const registrarPonto = mutation({
export const listarRegistrosDia = query({
args: {
data: v.optional(v.string()), // YYYY-MM-DD, se não fornecido usa hoje
_refresh: v.optional(v.number()), // Parâmetro usado pelo frontend para forçar refresh
_refresh: v.optional(v.number()) // Parâmetro usado pelo frontend para forçar refresh
},
handler: async (ctx, args) => {
const usuario = await getCurrentUserFunction(ctx);
@@ -806,20 +825,26 @@ export const listarRegistrosDia = query({
const registros = await ctx.db
.query('registrosPonto')
.withIndex('by_funcionario_data', (q) => q.eq('funcionarioId', funcionarioId).eq('data', data))
.withIndex('by_funcionario_data', (q) =>
q.eq('funcionarioId', funcionarioId).eq('data', data)
)
.order('asc')
.collect();
console.log('[listarRegistrosDia] Registros encontrados:', registros.length, registros.map(r => ({
_id: r._id,
tipo: r.tipo,
data: r.data,
hora: r.hora,
minuto: r.minuto
})));
console.log(
'[listarRegistrosDia] Registros encontrados:',
registros.length,
registros.map((r) => ({
_id: r._id,
tipo: r.tipo,
data: r.data,
hora: r.hora,
minuto: r.minuto
}))
);
return registros;
},
}
});
/**
@@ -828,7 +853,7 @@ export const listarRegistrosDia = query({
export const obterSaldoDiario = query({
args: {
funcionarioId: v.id('funcionarios'),
data: v.string(), // YYYY-MM-DD
data: v.string() // YYYY-MM-DD
},
handler: async (ctx, args) => {
// Buscar banco de horas do dia
@@ -844,7 +869,7 @@ export const obterSaldoDiario = query({
saldoMinutos: 0,
horas: 0,
minutos: 0,
positivo: true,
positivo: true
};
}
@@ -856,9 +881,9 @@ export const obterSaldoDiario = query({
saldoMinutos: bancoHoras.saldoMinutos,
horas,
minutos,
positivo,
positivo
};
},
}
});
/**
@@ -868,7 +893,7 @@ export const listarRegistrosPeriodo = query({
args: {
funcionarioId: v.optional(v.id('funcionarios')),
dataInicio: v.string(), // YYYY-MM-DD
dataFim: v.string(), // YYYY-MM-DD
dataFim: v.string() // YYYY-MM-DD
},
handler: async (ctx, args) => {
const usuario = await getCurrentUserFunction(ctx);
@@ -890,9 +915,9 @@ export const listarRegistrosPeriodo = query({
// Validar formato YYYY-MM-DD
const dataInicioRegex = /^\d{4}-\d{2}-\d{2}$/;
if (!dataInicioRegex.test(args.dataInicio) || !dataInicioRegex.test(args.dataFim)) {
console.warn('[listarRegistrosPeriodo] Formato de data inválido', {
dataInicio: args.dataInicio,
dataFim: args.dataFim
console.warn('[listarRegistrosPeriodo] Formato de data inválido', {
dataInicio: args.dataInicio,
dataFim: args.dataFim
});
return [];
}
@@ -905,18 +930,18 @@ export const listarRegistrosPeriodo = query({
});
let registrosFiltrados;
// Se funcionário foi especificado, usar índice por funcionário e data (mais eficiente)
if (args.funcionarioId) {
// Garantir que funcionarioId não é undefined para TypeScript
const funcionarioId = args.funcionarioId;
// Buscar todos os registros do funcionário
const todosRegistrosFuncionario = await ctx.db
.query('registrosPonto')
.withIndex('by_funcionario_data', (q) => q.eq('funcionarioId', funcionarioId))
.collect();
// Filtrar por período de data usando comparação de strings (formato YYYY-MM-DD)
registrosFiltrados = todosRegistrosFuncionario.filter((r) => {
// Comparação de strings funciona para formato YYYY-MM-DD
@@ -928,47 +953,47 @@ export const listarRegistrosPeriodo = query({
// Tentar usar índice por data primeiro
const registros = await ctx.db
.query('registrosPonto')
.withIndex('by_data', (q) =>
q.gte('data', args.dataInicio).lte('data', args.dataFim)
)
.withIndex('by_data', (q) => q.gte('data', args.dataInicio).lte('data', args.dataFim))
.collect();
console.log('[listarRegistrosPeriodo] Registros do índice by_data:', registros.length);
// Garantir que as datas estão no formato correto e filtrar novamente para garantir
registrosFiltrados = registros.filter((r) => {
// Comparação de strings funciona para formato YYYY-MM-DD
return r.data >= args.dataInicio && r.data <= args.dataFim;
});
console.log('[listarRegistrosPeriodo] Registros após filtro:', registrosFiltrados.length);
} catch (error) {
console.error('[listarRegistrosPeriodo] Erro ao buscar registros:', error);
// Fallback: buscar todos e filtrar manualmente
const todosRegistros = await ctx.db
.query('registrosPonto')
.collect();
const todosRegistros = await ctx.db.query('registrosPonto').collect();
registrosFiltrados = todosRegistros.filter((r) => {
return r.data >= args.dataInicio && r.data <= args.dataFim;
});
console.log('[listarRegistrosPeriodo] Fallback - registros encontrados:', registrosFiltrados.length);
console.log(
'[listarRegistrosPeriodo] Fallback - registros encontrados:',
registrosFiltrados.length
);
}
}
console.log('[listarRegistrosPeriodo] Registros encontrados antes de buscar funcionários:', registrosFiltrados.length);
console.log(
'[listarRegistrosPeriodo] Registros encontrados antes de buscar funcionários:',
registrosFiltrados.length
);
// Buscar informações dos funcionários
const funcionariosIds = new Set(registrosFiltrados.map((r) => r.funcionarioId));
const funcionarios = await Promise.all(
Array.from(funcionariosIds).map((id) => ctx.db.get(id))
);
const funcionarios = await Promise.all(Array.from(funcionariosIds).map((id) => ctx.db.get(id)));
// Buscar saldos diários para cada data/funcionário
const saldosPorDataFuncionario: Record<string, number> = {};
const datasUnicas = new Set(registrosFiltrados.map((r) => `${r.funcionarioId}-${r.data}`));
for (const chave of datasUnicas) {
const [funcId, data] = chave.split('-');
const bancoHoras = await ctx.db
@@ -977,19 +1002,22 @@ export const listarRegistrosPeriodo = query({
q.eq('funcionarioId', funcId as Id<'funcionarios'>).eq('data', data)
)
.first();
if (bancoHoras) {
saldosPorDataFuncionario[chave] = bancoHoras.saldoMinutos;
}
}
console.log('[listarRegistrosPeriodo] Total de registros a retornar:', registrosFiltrados.length);
console.log(
'[listarRegistrosPeriodo] Total de registros a retornar:',
registrosFiltrados.length
);
// Buscar fotos de perfil dos funcionários
const funcionariosComFoto = await Promise.all(
funcionarios.map(async (funcionario) => {
if (!funcionario) return { funcionario: null, fotoPerfilUrl: null };
let fotoPerfilUrl: string | null = null;
const usuario = await ctx.db
.query('usuarios')
@@ -998,13 +1026,15 @@ export const listarRegistrosPeriodo = query({
if (usuario?.fotoPerfil) {
fotoPerfilUrl = await ctx.storage.getUrl(usuario.fotoPerfil);
}
return { funcionario, fotoPerfilUrl };
})
);
return registrosFiltrados.map((registro) => {
const funcionarioComFoto = funcionariosComFoto.find((f) => f.funcionario?._id === registro.funcionarioId);
const funcionarioComFoto = funcionariosComFoto.find(
(f) => f.funcionario?._id === registro.funcionarioId
);
const funcionario = funcionarioComFoto?.funcionario;
const fotoPerfilUrl = funcionarioComFoto?.fotoPerfilUrl || null;
const chave = `${registro.funcionarioId}-${registro.data}`;
@@ -1019,7 +1049,7 @@ export const listarRegistrosPeriodo = query({
? {
nome: funcionario.nome,
matricula: funcionario.matricula,
descricaoCargo: funcionario.descricaoCargo,
descricaoCargo: funcionario.descricaoCargo
}
: null,
fotoPerfilUrl,
@@ -1027,11 +1057,11 @@ export const listarRegistrosPeriodo = query({
saldoMinutos,
horas,
minutos,
positivo,
},
positivo
}
};
});
},
}
});
/**
@@ -1041,7 +1071,7 @@ export const obterEstatisticas = query({
args: {
dataInicio: v.string(), // YYYY-MM-DD
dataFim: v.string(), // YYYY-MM-DD
funcionarioId: v.optional(v.id('funcionarios')),
funcionarioId: v.optional(v.id('funcionarios'))
},
handler: async (ctx, args) => {
const usuario = await getCurrentUserFunction(ctx);
@@ -1053,7 +1083,7 @@ export const obterEstatisticas = query({
foraDoPrazo: 0,
totalFuncionarios: 0,
funcionariosDentroPrazo: 0,
funcionariosForaPrazo: 0,
funcionariosForaPrazo: 0
};
}
@@ -1091,9 +1121,9 @@ export const obterEstatisticas = query({
foraDoPrazo,
totalFuncionarios,
funcionariosDentroPrazo,
funcionariosForaPrazo,
funcionariosForaPrazo
};
},
}
});
/**
@@ -1101,7 +1131,7 @@ export const obterEstatisticas = query({
*/
export const obterRegistro = query({
args: {
registroId: v.id('registrosPonto'),
registroId: v.id('registrosPonto')
},
handler: async (ctx, args) => {
const usuario = await getCurrentUserFunction(ctx);
@@ -1143,13 +1173,13 @@ export const obterRegistro = query({
simbolo: simbolo
? {
nome: simbolo.nome,
tipo: simbolo.tipo,
tipo: simbolo.tipo
}
: null,
: null
}
: null,
: null
};
},
}
});
/**
@@ -1163,7 +1193,9 @@ function calcularCargaHorariaDiaria(config: {
}): number {
const [horaEntrada, minutoEntrada] = config.horarioEntrada.split(':').map(Number);
const [horaSaidaAlmoco, minutoSaidaAlmoco] = config.horarioSaidaAlmoco.split(':').map(Number);
const [horaRetornoAlmoco, minutoRetornoAlmoco] = config.horarioRetornoAlmoco.split(':').map(Number);
const [horaRetornoAlmoco, minutoRetornoAlmoco] = config.horarioRetornoAlmoco
.split(':')
.map(Number);
const [horaSaida, minutoSaida] = config.horarioSaida.split(':').map(Number);
const minutosEntrada = horaEntrada * 60 + minutoEntrada;
@@ -1181,11 +1213,13 @@ function calcularCargaHorariaDiaria(config: {
/**
* Calcula horas trabalhadas do dia baseado nos registros
*/
function calcularHorasTrabalhadas(registros: Array<{
tipo: string;
hora: number;
minuto: number;
}>): number {
function calcularHorasTrabalhadas(
registros: Array<{
tipo: string;
hora: number;
minuto: number;
}>
): number {
// Ordenar registros por timestamp
const registrosOrdenados = [...registros].sort((a, b) => {
const minutosA = a.hora * 60 + a.minuto;
@@ -1268,7 +1302,7 @@ async function atualizarBancoHoras(
horasTrabalhadas,
saldoMinutos,
registrosPontoIds,
calculadoEm: Date.now(),
calculadoEm: Date.now()
});
} else {
// Criar novo
@@ -1279,7 +1313,7 @@ async function atualizarBancoHoras(
horasTrabalhadas,
saldoMinutos,
registrosPontoIds,
calculadoEm: Date.now(),
calculadoEm: Date.now()
});
}
}
@@ -1291,7 +1325,7 @@ export const obterHistoricoESaldoDia = query({
args: {
funcionarioId: v.id('funcionarios'),
data: v.string(), // YYYY-MM-DD
_refresh: v.optional(v.number()), // Parâmetro usado pelo frontend para forçar refresh
_refresh: v.optional(v.number()) // Parâmetro usado pelo frontend para forçar refresh
},
handler: async (ctx, args) => {
const usuario = await getCurrentUserFunction(ctx);
@@ -1302,7 +1336,7 @@ export const obterHistoricoESaldoDia = query({
registros: [],
cargaHorariaDiaria: 0,
horasTrabalhadas: 0,
saldoMinutos: 0,
saldoMinutos: 0
};
}
@@ -1319,7 +1353,7 @@ export const obterHistoricoESaldoDia = query({
)
.order('asc')
.collect();
console.log('[obterHistoricoESaldoDia] Registros encontrados:', registros.length, {
funcionarioId: args.funcionarioId,
data: args.data
@@ -1336,7 +1370,7 @@ export const obterHistoricoESaldoDia = query({
registros: [],
cargaHorariaDiaria: 0,
horasTrabalhadas: 0,
saldoMinutos: 0,
saldoMinutos: 0
};
}
@@ -1357,10 +1391,10 @@ export const obterHistoricoESaldoDia = query({
saldoFormatado: {
horas,
minutos,
positivo,
},
positivo
}
};
},
}
});
/**
@@ -1368,7 +1402,7 @@ export const obterHistoricoESaldoDia = query({
*/
export const obterBancoHorasFuncionario = query({
args: {
funcionarioId: v.id('funcionarios'),
funcionarioId: v.id('funcionarios')
},
handler: async (ctx, args) => {
const usuario = await getCurrentUserFunction(ctx);
@@ -1394,9 +1428,9 @@ export const obterBancoHorasFuncionario = query({
return {
bancosHoras,
saldoAcumuladoMinutos,
totalDias: bancosHoras.length,
totalDias: bancosHoras.length
};
},
}
});
/**
@@ -1432,7 +1466,7 @@ export const editarRegistroPonto = mutation({
motivoId: v.optional(v.string()),
motivoTipo: v.optional(v.string()),
motivoDescricao: v.optional(v.string()),
observacoes: v.optional(v.string()),
observacoes: v.optional(v.string())
},
handler: async (ctx, args) => {
const usuario = await getCurrentUserFunction(ctx);
@@ -1460,7 +1494,7 @@ export const editarRegistroPonto = mutation({
await ctx.db.patch(args.registroId, {
hora: args.horaNova,
minuto: args.minutoNova,
editadoPorGestor: true,
editadoPorGestor: true
});
// Criar registro de homologação
@@ -1476,12 +1510,12 @@ export const editarRegistroPonto = mutation({
motivoTipo: args.motivoTipo,
motivoDescricao: args.motivoDescricao,
observacoes: args.observacoes,
criadoEm: Date.now(),
criadoEm: Date.now()
});
// Atualizar registro com ID da homologação
await ctx.db.patch(args.registroId, {
homologacaoId,
homologacaoId
});
// Recalcular banco de horas do dia
@@ -1495,7 +1529,7 @@ export const editarRegistroPonto = mutation({
}
return { success: true, homologacaoId };
},
}
});
/**
@@ -1511,7 +1545,7 @@ export const ajustarBancoHoras = mutation({
motivoId: v.optional(v.string()),
motivoTipo: v.optional(v.string()),
motivoDescricao: v.optional(v.string()),
observacoes: v.optional(v.string()),
observacoes: v.optional(v.string())
},
handler: async (ctx, args) => {
const usuario = await getCurrentUserFunction(ctx);
@@ -1526,8 +1560,7 @@ export const ajustarBancoHoras = mutation({
}
// Calcular ajuste em minutos
const ajusteMinutos =
args.periodoDias * 24 * 60 + args.periodoHoras * 60 + args.periodoMinutos;
const ajusteMinutos = args.periodoDias * 24 * 60 + args.periodoHoras * 60 + args.periodoMinutos;
// Aplicar sinal baseado no tipo de ajuste
let ajusteFinal = ajusteMinutos;
@@ -1547,7 +1580,7 @@ export const ajustarBancoHoras = mutation({
if (bancoHorasAtual) {
// Atualizar saldo do dia atual
await ctx.db.patch(bancoHorasAtual._id, {
saldoMinutos: bancoHorasAtual.saldoMinutos + ajusteFinal,
saldoMinutos: bancoHorasAtual.saldoMinutos + ajusteFinal
});
} else {
// Criar novo registro de banco de horas para o ajuste
@@ -1569,7 +1602,7 @@ export const ajustarBancoHoras = mutation({
horasTrabalhadas: 0,
saldoMinutos: ajusteFinal,
registrosPontoIds: [],
calculadoEm: Date.now(),
calculadoEm: Date.now()
});
}
@@ -1586,11 +1619,11 @@ export const ajustarBancoHoras = mutation({
periodoHoras: args.periodoHoras,
periodoMinutos: args.periodoMinutos,
ajusteMinutos: ajusteFinal,
criadoEm: Date.now(),
criadoEm: Date.now()
});
return { success: true, homologacaoId, ajusteMinutos: ajusteFinal };
},
}
});
/**
@@ -1598,7 +1631,7 @@ export const ajustarBancoHoras = mutation({
*/
export const listarHomologacoes = query({
args: {
funcionarioId: v.optional(v.id('funcionarios')),
funcionarioId: v.optional(v.id('funcionarios'))
},
handler: async (ctx, args) => {
const usuario = await getCurrentUserFunction(ctx);
@@ -1656,27 +1689,27 @@ export const listarHomologacoes = query({
funcionario: funcionario
? {
nome: funcionario.nome,
matricula: funcionario.matricula,
matricula: funcionario.matricula
}
: null,
fotoPerfilUrl,
gestor: gestor
? {
nome: gestor.nome,
nome: gestor.nome
}
: null,
registro: registro
? {
data: registro.data,
tipo: registro.tipo,
tipo: registro.tipo
}
: null,
: null
};
})
);
return homologacoesComDetalhes;
},
}
});
/**
@@ -1684,7 +1717,7 @@ export const listarHomologacoes = query({
*/
export const excluirHomologacao = mutation({
args: {
homologacaoId: v.id('homologacoesPonto'),
homologacaoId: v.id('homologacoesPonto')
},
handler: async (ctx, args) => {
const usuario = await getCurrentUserFunction(ctx);
@@ -1698,7 +1731,11 @@ export const excluirHomologacao = mutation({
}
// Verificar se é gestor do funcionário
const isGestor = await verificarGestorDoFuncionario(ctx, usuario._id, homologacao.funcionarioId);
const isGestor = await verificarGestorDoFuncionario(
ctx,
usuario._id,
homologacao.funcionarioId
);
if (!isGestor && homologacao.gestorId !== usuario._id) {
throw new Error('Você não tem permissão para excluir esta homologação');
}
@@ -1709,7 +1746,7 @@ export const excluirHomologacao = mutation({
if (registro && registro.homologacaoId === args.homologacaoId) {
await ctx.db.patch(homologacao.registroId, {
homologacaoId: undefined,
editadoPorGestor: false,
editadoPorGestor: false
});
}
}
@@ -1718,7 +1755,7 @@ export const excluirHomologacao = mutation({
await ctx.db.delete(args.homologacaoId);
return { success: true };
},
}
});
/**
@@ -1744,10 +1781,10 @@ export const obterMotivosAtestados = query({
'Ajuste Administrativo',
'Compensação de Horas',
'Abono',
'Desconto em Folha',
],
'Desconto em Folha'
]
};
},
}
});
/**
@@ -1763,7 +1800,7 @@ export const criarDispensaRegistro = mutation({
horaFim: v.number(),
minutoFim: v.number(),
motivo: v.string(),
isento: v.boolean(),
isento: v.boolean()
},
handler: async (ctx, args) => {
const usuario = await getCurrentUserFunction(ctx);
@@ -1798,11 +1835,11 @@ export const criarDispensaRegistro = mutation({
motivo: args.motivo,
isento: args.isento,
ativo: true,
criadoEm: Date.now(),
criadoEm: Date.now()
});
return { success: true, dispensaId };
},
}
});
/**
@@ -1810,7 +1847,7 @@ export const criarDispensaRegistro = mutation({
*/
export const removerDispensaRegistro = mutation({
args: {
dispensaId: v.id('dispensasRegistro'),
dispensaId: v.id('dispensasRegistro')
},
handler: async (ctx, args) => {
const usuario = await getCurrentUserFunction(ctx);
@@ -1831,11 +1868,11 @@ export const removerDispensaRegistro = mutation({
// Desativar dispensa
await ctx.db.patch(args.dispensaId, {
ativo: false,
ativo: false
});
return { success: true };
},
}
});
/**
@@ -1844,7 +1881,7 @@ export const removerDispensaRegistro = mutation({
export const listarDispensas = query({
args: {
funcionarioId: v.optional(v.id('funcionarios')),
apenasAtivas: v.optional(v.boolean()),
apenasAtivas: v.optional(v.boolean())
},
handler: async (ctx, args) => {
const usuario = await getCurrentUserFunction(ctx);
@@ -1923,22 +1960,22 @@ export const listarDispensas = query({
funcionario: funcionario
? {
nome: funcionario.nome,
matricula: funcionario.matricula,
matricula: funcionario.matricula
}
: null,
fotoPerfilUrl,
gestor: gestor
? {
nome: gestor.nome,
nome: gestor.nome
}
: null,
expirada,
expirada
};
})
);
return dispensasComDetalhes;
},
}
});
/**
@@ -1949,7 +1986,7 @@ export const verificarDispensaAtiva = query({
funcionarioId: v.id('funcionarios'),
data: v.string(), // YYYY-MM-DD
hora: v.optional(v.number()),
minuto: v.optional(v.number()),
minuto: v.optional(v.number())
},
handler: async (ctx, args) => {
const dispensas = await ctx.db
@@ -1966,7 +2003,7 @@ export const verificarDispensaAtiva = query({
return {
dispensado: true,
dispensa,
motivo: 'Isento de registro (caso excepcional)',
motivo: 'Isento de registro (caso excepcional)'
};
}
@@ -1992,7 +2029,7 @@ export const verificarDispensaAtiva = query({
return {
dispensado: true,
dispensa,
motivo: dispensa.motivo,
motivo: dispensa.motivo
};
}
} else {
@@ -2000,7 +2037,7 @@ export const verificarDispensaAtiva = query({
return {
dispensado: true,
dispensa,
motivo: dispensa.motivo,
motivo: dispensa.motivo
};
}
}
@@ -2009,8 +2046,7 @@ export const verificarDispensaAtiva = query({
return {
dispensado: false,
dispensa: null,
motivo: null,
motivo: null
};
},
}
});