import { v } from "convex/values"; import { mutation, query } from "./_generated/server"; import { Id, Doc } from "./_generated/dataModel"; import type { QueryCtx, MutationCtx } from "./_generated/server"; import { registrarAtividade } from "./logsAtividades"; // ========== HELPERS ========== /** * Helper function para obter usuário autenticado */ async function getUsuarioAutenticado(ctx: QueryCtx | MutationCtx) { const identity = await ctx.auth.getUserIdentity(); let usuarioAtual = null; if (identity && identity.email) { usuarioAtual = await ctx.db .query("usuarios") .withIndex("by_email", (q) => q.eq("email", identity.email!)) .first(); } if (!usuarioAtual) { const sessaoAtiva = await ctx.db .query("sessoes") .filter((q) => q.eq(q.field("ativo"), true)) .order("desc") .first(); if (sessaoAtiva) { usuarioAtual = await ctx.db.get(sessaoAtiva.usuarioId); } } return usuarioAtual; } /** * Helper para calcular dias entre duas datas */ function calcularDias(dataInicio: string, dataFim: string): number { const inicio = new Date(dataInicio); const fim = new Date(dataFim); const diffTime = Math.abs(fim.getTime() - inicio.getTime()); const diffDays = Math.ceil(diffTime / (1000 * 60 * 60 * 24)) + 1; return diffDays; } // ========== QUERIES ========== /** * Listar todos os atestados e licenças com detalhes do funcionário */ export const listarTodos = query({ args: {}, handler: async (ctx) => { try { const [atestados, licencas] = await Promise.all([ ctx.db.query("atestados").collect(), ctx.db.query("licencas").collect(), ]); const atestadosComDetalhes = await Promise.all( atestados.map(async (a) => { try { const funcionario = await ctx.db.get(a.funcionarioId); const criadoPor = await ctx.db.get(a.criadoPor); return { ...a, funcionario, criadoPorNome: criadoPor?.nome || "Sistema", dias: calcularDias(a.dataInicio, a.dataFim), status: new Date(a.dataFim) >= new Date() ? "ativo" : "finalizado", }; } catch (error) { console.error("Erro ao buscar detalhes do atestado:", error); return { ...a, funcionario: null, criadoPorNome: "Sistema", dias: calcularDias(a.dataInicio, a.dataFim), status: new Date(a.dataFim) >= new Date() ? "ativo" : "finalizado", }; } }) ); const licencasComDetalhes = await Promise.all( licencas.map(async (l) => { try { const funcionario = await ctx.db.get(l.funcionarioId); const criadoPor = await ctx.db.get(l.criadoPor); const licencaOriginal = l.licencaOriginalId ? await ctx.db.get(l.licencaOriginalId) : null; return { ...l, funcionario, criadoPorNome: criadoPor?.nome || "Sistema", licencaOriginal, dias: calcularDias(l.dataInicio, l.dataFim), status: new Date(l.dataFim) >= new Date() ? "ativo" : "finalizado", }; } catch (error) { console.error("Erro ao buscar detalhes da licença:", error); return { ...l, funcionario: null, criadoPorNome: "Sistema", licencaOriginal: null, dias: calcularDias(l.dataInicio, l.dataFim), status: new Date(l.dataFim) >= new Date() ? "ativo" : "finalizado", }; } }) ); return { atestados: atestadosComDetalhes.sort( (a, b) => b._creationTime - a._creationTime ), licencas: licencasComDetalhes.sort( (a, b) => b._creationTime - a._creationTime ), }; } catch (error) { console.error("Erro em listarTodos:", error); return { atestados: [], licencas: [], }; } }, }); /** * Listar por funcionário específico */ export const listarPorFuncionario = query({ args: { funcionarioId: v.id("funcionarios") }, handler: async (ctx, args) => { const [atestados, licencas] = await Promise.all([ ctx.db .query("atestados") .withIndex("by_funcionario", (q) => q.eq("funcionarioId", args.funcionarioId) ) .collect(), ctx.db .query("licencas") .withIndex("by_funcionario", (q) => q.eq("funcionarioId", args.funcionarioId) ) .collect(), ]); return { atestados: atestados.sort((a, b) => b._creationTime - a._creationTime), licencas: licencas.sort((a, b) => b._creationTime - a._creationTime), }; }, }); /** * Listar por período */ export const listarPorPeriodo = query({ args: { dataInicio: v.string(), dataFim: v.string(), }, handler: async (ctx, args) => { const dataInicioObj = new Date(args.dataInicio); const dataFimObj = new Date(args.dataFim); const atestados = await ctx.db.query("atestados").collect(); const licencas = await ctx.db.query("licencas").collect(); const atestadosFiltrados = atestados.filter((a) => { const inicio = new Date(a.dataInicio); const fim = new Date(a.dataFim); return ( (inicio >= dataInicioObj && inicio <= dataFimObj) || (fim >= dataInicioObj && fim <= dataFimObj) || (inicio <= dataInicioObj && fim >= dataFimObj) ); }); const licencasFiltradas = licencas.filter((l) => { const inicio = new Date(l.dataInicio); const fim = new Date(l.dataFim); return ( (inicio >= dataInicioObj && inicio <= dataFimObj) || (fim >= dataInicioObj && fim <= dataFimObj) || (inicio <= dataInicioObj && fim >= dataFimObj) ); }); return { atestados: atestadosFiltrados, licencas: licencasFiltradas, }; }, }); /** * Obter dados para gráficos */ export const obterDadosGraficos = query({ args: { periodo: v.optional(v.number()), // dias (padrão: 30) }, handler: async (ctx, args) => { try { const dias = args.periodo || 30; const dataLimite = Date.now() - dias * 24 * 60 * 60 * 1000; const [atestados, licencas] = await Promise.all([ ctx.db.query("atestados").collect(), ctx.db.query("licencas").collect(), ]); // Filtrar por período const atestadosFiltrados = atestados.filter( (a) => new Date(a.criadoEm) >= new Date(dataLimite) ); const licencasFiltradas = licencas.filter( (l) => new Date(l.criadoEm) >= new Date(dataLimite) ); // 1. Total de dias por tipo (para gráfico de barras) const totalDiasPorTipo: Record = { atestado_medico: 0, declaracao_comparecimento: 0, maternidade: 0, paternidade: 0, ferias: 0, }; atestadosFiltrados.forEach((a) => { const dias = calcularDias(a.dataInicio, a.dataFim); if (a.tipo === "atestado_medico") { totalDiasPorTipo.atestado_medico += dias; } else { totalDiasPorTipo.declaracao_comparecimento += dias; } }); licencasFiltradas.forEach((l) => { const dias = calcularDias(l.dataInicio, l.dataFim); if (l.tipo === "maternidade") { totalDiasPorTipo.maternidade += dias; } else { totalDiasPorTipo.paternidade += dias; } }); // Buscar férias do período try { const solicitacoesFerias = await ctx.db .query("solicitacoesFerias") .filter((q) => q.or( q.eq(q.field("status"), "aprovado"), q.eq(q.field("status"), "data_ajustada_aprovada") ) ) .collect(); solicitacoesFerias.forEach((s) => { if (s.periodos && Array.isArray(s.periodos)) { s.periodos.forEach((p: { dataInicio: string; dataFim: string }) => { const dias = calcularDias(p.dataInicio, p.dataFim); totalDiasPorTipo.ferias += dias; }); } }); } catch (error) { console.error("Erro ao buscar férias para gráfico:", error); } // 2. Tendências mensais (últimos 6 meses) const meses: Record< string, { atestado_medico: number; declaracao_comparecimento: number; maternidade: number; paternidade: number; ferias: number; } > = {}; const hoje = new Date(); for (let i = 5; i >= 0; i--) { const mesData = new Date(hoje.getFullYear(), hoje.getMonth() - i, 1); const mesKey = mesData.toLocaleDateString("pt-BR", { month: "short", year: "numeric", }); meses[mesKey] = { atestado_medico: 0, declaracao_comparecimento: 0, maternidade: 0, paternidade: 0, ferias: 0, }; } // Processar atestados para tendências mensais (usar todos, não apenas filtrados) atestados.forEach((item) => { try { const mesData = new Date(item.criadoEm); const mesKey = mesData.toLocaleDateString("pt-BR", { month: "short", year: "numeric", }); if (meses[mesKey]) { const dias = calcularDias(item.dataInicio, item.dataFim); if (item.tipo === "atestado_medico") { meses[mesKey].atestado_medico += dias; } else if (item.tipo === "declaracao_comparecimento") { meses[mesKey].declaracao_comparecimento += dias; } } } catch (error) { console.error("Erro ao processar atestado para tendências:", error); } }); // Processar licenças para tendências mensais (usar todas, não apenas filtradas) licencas.forEach((item) => { try { const mesData = new Date(item.criadoEm); const mesKey = mesData.toLocaleDateString("pt-BR", { month: "short", year: "numeric", }); if (meses[mesKey]) { const dias = calcularDias(item.dataInicio, item.dataFim); if (item.tipo === "maternidade") { meses[mesKey].maternidade += dias; } else if (item.tipo === "paternidade") { meses[mesKey].paternidade += dias; } } } catch (error) { console.error("Erro ao processar licença para tendências:", error); } }); // 3. Funcionários atualmente afastados const hojeStr = new Date().toISOString().split("T")[0]; const funcionariosAfastados: Array<{ funcionarioId: Id<"funcionarios">; funcionarioNome: string; tipo: string; dataInicio: string; dataFim: string; }> = []; // Processar atestados (verificar funcionários atualmente afastados) atestadosFiltrados.forEach((item) => { try { const inicio = new Date(item.dataInicio); const fim = new Date(item.dataFim); const hoje = new Date(hojeStr); if (hoje >= inicio && hoje <= fim) { funcionariosAfastados.push({ funcionarioId: item.funcionarioId, funcionarioNome: "Carregando...", tipo: item.tipo, dataInicio: item.dataInicio, dataFim: item.dataFim, }); } } catch (error) { console.error("Erro ao processar atestado:", error); } }); // Processar licenças (verificar funcionários atualmente afastados) licencasFiltradas.forEach((item) => { try { const inicio = new Date(item.dataInicio); const fim = new Date(item.dataFim); const hoje = new Date(hojeStr); if (hoje >= inicio && hoje <= fim) { funcionariosAfastados.push({ funcionarioId: item.funcionarioId, funcionarioNome: "Carregando...", tipo: item.tipo, dataInicio: item.dataInicio, dataFim: item.dataFim, }); } } catch (error) { console.error("Erro ao processar licença:", error); } }); // Buscar nomes dos funcionários const funcionariosAfastadosComNomes = await Promise.all( funcionariosAfastados.map(async (item) => { try { const funcionario = await ctx.db.get(item.funcionarioId); return { ...item, funcionarioNome: funcionario?.nome || "Desconhecido", }; } catch (error) { console.error("Erro ao buscar funcionário:", error); return { ...item, funcionarioNome: "Desconhecido", }; } }) ); return { totalDiasPorTipo: [ { tipo: "Atestado Médico", dias: totalDiasPorTipo.atestado_medico }, { tipo: "Declaração", dias: totalDiasPorTipo.declaracao_comparecimento, }, { tipo: "Licença Maternidade", dias: totalDiasPorTipo.maternidade }, { tipo: "Licença Paternidade", dias: totalDiasPorTipo.paternidade }, { tipo: "Férias", dias: totalDiasPorTipo.ferias }, ], tendenciasMensais: Object.entries(meses).map(([mes, dados]) => ({ mes, ...dados, })), funcionariosAfastados: funcionariosAfastadosComNomes, }; } catch (error) { console.error("Erro em obterDadosGraficos:", error); // Retornar dados vazios em caso de erro para não quebrar a página return { totalDiasPorTipo: [ { tipo: "Atestado Médico", dias: 0 }, { tipo: "Declaração", dias: 0 }, { tipo: "Licença Maternidade", dias: 0 }, { tipo: "Licença Paternidade", dias: 0 }, { tipo: "Férias", dias: 0 }, ], tendenciasMensais: [], funcionariosAfastados: [], }; } }, }); /** * Obter estatísticas para dashboard */ export const obterEstatisticas = query({ args: {}, handler: async (ctx) => { const hoje = new Date(); hoje.setHours(0, 0, 0, 0); const inicioMes = new Date(hoje.getFullYear(), hoje.getMonth(), 1); const fimMes = new Date(hoje.getFullYear(), hoje.getMonth() + 1, 0); const [atestados, licencas] = await Promise.all([ ctx.db.query("atestados").collect(), ctx.db.query("licencas").collect(), ]); // Atestados ativos const atestadosAtivos = atestados.filter( (a) => new Date(a.dataFim) >= hoje ); // Licenças ativas const licencasAtivas = licencas.filter( (l) => new Date(l.dataFim) >= hoje ); // Funcionários afastados hoje const funcionariosAfastadosHoje = new Set(); [...atestados, ...licencas].forEach((item) => { const inicio = new Date(item.dataInicio); const fim = new Date(item.dataFim); if (hoje >= inicio && hoje <= fim) { funcionariosAfastadosHoje.add(item.funcionarioId); } }); // Total de dias no mês let totalDiasMes = 0; [...atestados, ...licencas].forEach((item) => { const inicio = new Date(item.dataInicio); const fim = new Date(item.dataFim); if ( (inicio >= inicioMes && inicio <= fimMes) || (fim >= inicioMes && fim <= fimMes) || (inicio <= inicioMes && fim >= fimMes) ) { const dias = calcularDias(item.dataInicio, item.dataFim); totalDiasMes += dias; } }); return { totalAtestadosAtivos: atestadosAtivos.length, totalLicencasAtivas: licencasAtivas.length, funcionariosAfastadosHoje: funcionariosAfastadosHoje.size, totalDiasAfastamentoMes: totalDiasMes, }; }, }); /** * Obter eventos formatados para calendário */ export const obterEventosCalendario = query({ args: { dataInicio: v.optional(v.string()), dataFim: v.optional(v.string()), tipoFiltro: v.optional( v.union( v.literal("todos"), v.literal("atestado_medico"), v.literal("declaracao_comparecimento"), v.literal("maternidade"), v.literal("paternidade"), v.literal("ferias") ) ), }, handler: async (ctx, args) => { const eventos: Array<{ id: string; title: string; start: string; end: string; color: string; tipo: string; funcionarioNome: string; funcionarioId: string; }> = []; try { // Buscar atestados if ( !args.tipoFiltro || args.tipoFiltro === "todos" || args.tipoFiltro === "atestado_medico" || args.tipoFiltro === "declaracao_comparecimento" ) { try { const atestados = await ctx.db.query("atestados").collect(); for (const atestado of atestados) { try { if ( args.tipoFiltro && args.tipoFiltro !== "todos" && atestado.tipo !== args.tipoFiltro ) { continue; } const funcionario = await ctx.db.get(atestado.funcionarioId); if (!funcionario) continue; if (!atestado.dataInicio || !atestado.dataFim) continue; const cor = atestado.tipo === "atestado_medico" ? "#ef4444" : "#f97316"; // vermelho ou laranja eventos.push({ id: `atestado-${atestado._id}`, title: `${funcionario.nome} - ${ atestado.tipo === "atestado_medico" ? "Atestado Médico" : "Declaração" }`, start: atestado.dataInicio, end: atestado.dataFim, color: cor, tipo: atestado.tipo, funcionarioNome: funcionario.nome, funcionarioId: funcionario._id, }); } catch (error) { console.error(`Erro ao processar atestado ${atestado._id}:`, error); continue; } } } catch (error) { console.error("Erro ao buscar atestados:", error); } } // Buscar licenças if ( !args.tipoFiltro || args.tipoFiltro === "todos" || args.tipoFiltro === "maternidade" || args.tipoFiltro === "paternidade" ) { try { const licencas = await ctx.db.query("licencas").collect(); for (const licenca of licencas) { try { if ( args.tipoFiltro && args.tipoFiltro !== "todos" && licenca.tipo !== args.tipoFiltro ) { continue; } const funcionario = await ctx.db.get(licenca.funcionarioId); if (!funcionario) continue; if (!licenca.dataInicio || !licenca.dataFim) continue; const cor = licenca.tipo === "maternidade" ? "#ec4899" : "#3b82f6"; // rosa ou azul eventos.push({ id: `licenca-${licenca._id}`, title: `${funcionario.nome} - Licença ${ licenca.tipo === "maternidade" ? "Maternidade" : "Paternidade" }`, start: licenca.dataInicio, end: licenca.dataFim, color: cor, tipo: licenca.tipo, funcionarioNome: funcionario.nome, funcionarioId: funcionario._id, }); } catch (error) { console.error(`Erro ao processar licença ${licenca._id}:`, error); continue; } } } catch (error) { console.error("Erro ao buscar licenças:", error); } } } catch (error) { console.error("Erro geral em obterEventosCalendario:", error); return eventos; // Retorna eventos já coletados mesmo se houver erro } // Integrar com férias (se não estiver filtrando por tipo específico) if (!args.tipoFiltro || args.tipoFiltro === "todos" || args.tipoFiltro === "ferias") { try { // Buscar solicitações de férias aprovadas const solicitacoesFerias = await ctx.db .query("solicitacoesFerias") .filter((q) => q.or( q.eq(q.field("status"), "aprovado"), q.eq(q.field("status"), "data_ajustada_aprovada") ) ) .collect(); for (const solicitacao of solicitacoesFerias) { try { const funcionario = await ctx.db.get(solicitacao.funcionarioId); if (!funcionario) continue; // Verificar se periodos existe e é um array if (!solicitacao.periodos || !Array.isArray(solicitacao.periodos)) { continue; } for (const periodo of solicitacao.periodos) { if (!periodo.dataInicio || !periodo.dataFim) continue; eventos.push({ id: `ferias-${solicitacao._id}-${periodo.dataInicio}`, title: `${funcionario.nome} - Férias`, start: periodo.dataInicio, end: periodo.dataFim, color: "#10b981", // verde tipo: "ferias", funcionarioNome: funcionario.nome, funcionarioId: funcionario._id, }); } } catch (error) { console.error(`Erro ao processar solicitação de férias ${solicitacao._id}:`, error); continue; } } } catch (error) { console.error("Erro ao buscar solicitações de férias:", error); // Continua mesmo se houver erro ao buscar férias } } // Filtrar por período se fornecido if (args.dataInicio && args.dataFim) { const inicio = new Date(args.dataInicio); const fim = new Date(args.dataFim); return eventos.filter((e) => { const eventStart = new Date(e.start); const eventEnd = new Date(e.end); return ( (eventStart >= inicio && eventStart <= fim) || (eventEnd >= inicio && eventEnd <= fim) || (eventStart <= inicio && eventEnd >= fim) ); }); } return eventos; }, }); // ========== MUTATIONS ========== /** * Gerar URL para upload de documentos */ export const generateUploadUrl = mutation({ args: {}, returns: v.string(), handler: async (ctx) => { const usuario = await getUsuarioAutenticado(ctx); if (!usuario) throw new Error("Não autenticado"); return await ctx.storage.generateUploadUrl(); }, }); /** * Criar atestado médico */ export const criarAtestadoMedico = mutation({ args: { funcionarioId: v.id("funcionarios"), dataInicio: v.string(), dataFim: v.string(), cid: v.string(), observacoes: v.optional(v.string()), documentoId: v.optional(v.id("_storage")), }, returns: v.id("atestados"), handler: async (ctx, args) => { const usuario = await getUsuarioAutenticado(ctx); if (!usuario) throw new Error("Não autenticado"); // Validar datas if (new Date(args.dataFim) < new Date(args.dataInicio)) { throw new Error("Data fim deve ser maior ou igual à data início"); } const atestadoId = await ctx.db.insert("atestados", { funcionarioId: args.funcionarioId, tipo: "atestado_medico", dataInicio: args.dataInicio, dataFim: args.dataFim, cid: args.cid, observacoes: args.observacoes, documentoId: args.documentoId, criadoPor: usuario._id, criadoEm: Date.now(), }); await registrarAtividade( ctx, usuario._id, "criar", "atestados", `Atestado médico criado para funcionário ${args.funcionarioId}`, atestadoId ); return atestadoId; }, }); /** * Criar declaração de comparecimento */ export const criarDeclaracaoComparecimento = mutation({ args: { funcionarioId: v.id("funcionarios"), dataInicio: v.string(), dataFim: v.string(), observacoes: v.optional(v.string()), documentoId: v.optional(v.id("_storage")), }, returns: v.id("atestados"), handler: async (ctx, args) => { const usuario = await getUsuarioAutenticado(ctx); if (!usuario) throw new Error("Não autenticado"); // Validar datas if (new Date(args.dataFim) < new Date(args.dataInicio)) { throw new Error("Data fim deve ser maior ou igual à data início"); } const atestadoId = await ctx.db.insert("atestados", { funcionarioId: args.funcionarioId, tipo: "declaracao_comparecimento", dataInicio: args.dataInicio, dataFim: args.dataFim, observacoes: args.observacoes, documentoId: args.documentoId, criadoPor: usuario._id, criadoEm: Date.now(), }); await registrarAtividade( ctx, usuario._id, "criar", "atestados", `Declaração de comparecimento criada para funcionário ${args.funcionarioId}`, atestadoId ); return atestadoId; }, }); /** * Criar licença maternidade */ export const criarLicencaMaternidade = mutation({ args: { funcionarioId: v.id("funcionarios"), dataInicio: v.string(), dataFim: v.string(), observacoes: v.optional(v.string()), documentoId: v.optional(v.id("_storage")), licencaOriginalId: v.optional(v.id("licencas")), }, returns: v.id("licencas"), handler: async (ctx, args) => { const usuario = await getUsuarioAutenticado(ctx); if (!usuario) throw new Error("Não autenticado"); // Validar datas if (new Date(args.dataFim) < new Date(args.dataInicio)) { throw new Error("Data fim deve ser maior ou igual à data início"); } const ehProrrogacao = !!args.licencaOriginalId; if (ehProrrogacao && !args.licencaOriginalId) { throw new Error("Licença original é obrigatória para prorrogação"); } const licencaId = await ctx.db.insert("licencas", { funcionarioId: args.funcionarioId, tipo: "maternidade", dataInicio: args.dataInicio, dataFim: args.dataFim, observacoes: args.observacoes, documentoId: args.documentoId, licencaOriginalId: args.licencaOriginalId, ehProrrogacao, criadoPor: usuario._id, criadoEm: Date.now(), }); await registrarAtividade( ctx, usuario._id, "criar", "licencas", `Licença maternidade criada para funcionário ${args.funcionarioId}${ehProrrogacao ? " (prorrogação)" : ""}`, licencaId ); return licencaId; }, }); /** * Criar licença paternidade */ export const criarLicencaPaternidade = mutation({ args: { funcionarioId: v.id("funcionarios"), dataInicio: v.string(), dataFim: v.string(), observacoes: v.optional(v.string()), documentoId: v.optional(v.id("_storage")), }, returns: v.id("licencas"), handler: async (ctx, args) => { const usuario = await getUsuarioAutenticado(ctx); if (!usuario) throw new Error("Não autenticado"); // Validar datas if (new Date(args.dataFim) < new Date(args.dataInicio)) { throw new Error("Data fim deve ser maior ou igual à data início"); } const licencaId = await ctx.db.insert("licencas", { funcionarioId: args.funcionarioId, tipo: "paternidade", dataInicio: args.dataInicio, dataFim: args.dataFim, observacoes: args.observacoes, documentoId: args.documentoId, ehProrrogacao: false, criadoPor: usuario._id, criadoEm: Date.now(), }); await registrarAtividade( ctx, usuario._id, "criar", "licencas", `Licença paternidade criada para funcionário ${args.funcionarioId}`, licencaId ); return licencaId; }, }); /** * Prorrogar licença maternidade */ export const prorrogarLicencaMaternidade = mutation({ args: { licencaOriginalId: v.id("licencas"), dataInicio: v.string(), dataFim: v.string(), observacoes: v.optional(v.string()), documentoId: v.optional(v.id("_storage")), }, returns: v.id("licencas"), handler: async (ctx, args) => { const usuario = await getUsuarioAutenticado(ctx); if (!usuario) throw new Error("Não autenticado"); const licencaOriginal = await ctx.db.get(args.licencaOriginalId); if (!licencaOriginal) { throw new Error("Licença original não encontrada"); } if (licencaOriginal.tipo !== "maternidade") { throw new Error("Apenas licenças de maternidade podem ser prorrogadas"); } // Validar datas if (new Date(args.dataFim) < new Date(args.dataInicio)) { throw new Error("Data fim deve ser maior ou igual à data início"); } const prorrogacaoId = await ctx.db.insert("licencas", { funcionarioId: licencaOriginal.funcionarioId, tipo: "maternidade", dataInicio: args.dataInicio, dataFim: args.dataFim, observacoes: args.observacoes, documentoId: args.documentoId, licencaOriginalId: args.licencaOriginalId, ehProrrogacao: true, criadoPor: usuario._id, criadoEm: Date.now(), }); await registrarAtividade( ctx, usuario._id, "criar", "licencas", `Prorrogação de licença maternidade criada para funcionário ${licencaOriginal.funcionarioId}`, prorrogacaoId ); return prorrogacaoId; }, }); /** * Excluir atestado */ export const excluirAtestado = mutation({ args: { id: v.id("atestados"), }, returns: v.null(), handler: async (ctx, args) => { const usuario = await getUsuarioAutenticado(ctx); if (!usuario) throw new Error("Não autenticado"); const atestado = await ctx.db.get(args.id); if (!atestado) throw new Error("Atestado não encontrado"); await ctx.db.delete(args.id); await registrarAtividade( ctx, usuario._id, "excluir", "atestados", `Atestado excluído: ${args.id}`, args.id ); return null; }, }); /** * Excluir licença */ export const excluirLicenca = mutation({ args: { id: v.id("licencas"), }, returns: v.null(), handler: async (ctx, args) => { const usuario = await getUsuarioAutenticado(ctx); if (!usuario) throw new Error("Não autenticado"); const licenca = await ctx.db.get(args.id); if (!licenca) throw new Error("Licença não encontrada"); await ctx.db.delete(args.id); await registrarAtividade( ctx, usuario._id, "excluir", "licencas", `Licença excluída: ${args.id}`, args.id ); return null; }, });