feat: implement almoxarifado features including new category in recursos-humanos, configuration options in TI, and backend support for inventory management, enhancing user navigation and system functionality

This commit is contained in:
2025-12-18 16:21:08 -03:00
parent 1eb454815f
commit 367cda7b95
22 changed files with 4831 additions and 2 deletions

View File

@@ -0,0 +1,165 @@
import { v } from 'convex/values';
import { internal, internalQuery, mutation, query } from './_generated/server';
import { getCurrentUserFunction } from './auth';
export const obterConfiguracao = query({
args: {},
handler: async (ctx) => {
// Verificar se usuário tem permissão de TI
await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, {
recurso: 'almoxarifado',
acao: 'configurar'
});
const config = await ctx.db
.query('configuracoesAlmoxarifado')
.filter((q) => q.eq(q.field('ativo'), true))
.first();
// Se não existe configuração, retornar valores padrão
if (!config) {
return {
estoqueMinimoPadrao: 10,
diasAntecedenciaAlerta: 7,
permitirEstoqueNegativo: false,
requerAprovacaoRequisicao: true,
rolesAprovacao: [],
emailAlertasAtivo: false,
emailsDestinatarios: [],
periodicidadeInventario: 30,
ultimoInventario: undefined,
ativo: true
};
}
return config;
}
});
export const atualizarConfiguracao = mutation({
args: {
estoqueMinimoPadrao: v.optional(v.number()),
diasAntecedenciaAlerta: v.optional(v.number()),
permitirEstoqueNegativo: v.optional(v.boolean()),
requerAprovacaoRequisicao: v.optional(v.boolean()),
rolesAprovacao: v.optional(v.array(v.string())),
emailAlertasAtivo: v.optional(v.boolean()),
emailsDestinatarios: v.optional(v.array(v.string())),
periodicidadeInventario: v.optional(v.number()),
ultimoInventario: v.optional(v.number())
},
handler: async (ctx, args) => {
// Verificar se usuário tem permissão de TI_MASTER
await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, {
recurso: 'almoxarifado',
acao: 'configurar'
});
const usuario = await getCurrentUserFunction(ctx);
if (!usuario) throw new Error('Usuário não autenticado');
// Buscar configuração existente
let config = await ctx.db
.query('configuracoesAlmoxarifado')
.filter((q) => q.eq(q.field('ativo'), true))
.first();
const dadosAnteriores = config ? { ...config } : undefined;
if (config) {
// Desativar configuração antiga
await ctx.db.patch(config._id, { ativo: false });
// Criar nova configuração
const dadosNovos = {
...config,
...args,
ativo: true,
atualizadoPor: usuario._id,
atualizadoEm: Date.now()
};
const novaConfigId = await ctx.db.insert('configuracoesAlmoxarifado', dadosNovos);
// Registrar histórico
if (usuario) {
await ctx.db.insert('historicoAlteracoes', {
tipoEntidade: 'configuracao',
entidadeId: novaConfigId,
acao: 'edicao',
usuarioId: usuario._id,
dadosAnteriores: dadosAnteriores ? JSON.stringify(dadosAnteriores) : undefined,
dadosNovos: JSON.stringify(dadosNovos),
timestamp: Date.now(),
observacoes: 'Atualização de configurações do almoxarifado'
});
}
return novaConfigId;
} else {
// Criar primeira configuração
const dadosNovos = {
estoqueMinimoPadrao: args.estoqueMinimoPadrao ?? 10,
diasAntecedenciaAlerta: args.diasAntecedenciaAlerta ?? 7,
permitirEstoqueNegativo: args.permitirEstoqueNegativo ?? false,
requerAprovacaoRequisicao: args.requerAprovacaoRequisicao ?? true,
rolesAprovacao: args.rolesAprovacao ?? [],
emailAlertasAtivo: args.emailAlertasAtivo ?? false,
emailsDestinatarios: args.emailsDestinatarios ?? [],
periodicidadeInventario: args.periodicidadeInventario ?? 30,
ultimoInventario: args.ultimoInventario,
ativo: true,
atualizadoPor: usuario._id,
atualizadoEm: Date.now()
};
const novaConfigId = await ctx.db.insert('configuracoesAlmoxarifado', dadosNovos);
// Registrar histórico
if (usuario) {
await ctx.db.insert('historicoAlteracoes', {
tipoEntidade: 'configuracao',
entidadeId: novaConfigId,
acao: 'criacao',
usuarioId: usuario._id,
dadosAnteriores: undefined,
dadosNovos: JSON.stringify(dadosNovos),
timestamp: Date.now(),
observacoes: 'Criação de configurações do almoxarifado'
});
}
return novaConfigId;
}
}
});
// ========== INTERNAL QUERIES ==========
export const obterConfiguracaoInterno = internalQuery({
args: {},
handler: async (ctx) => {
const config = await ctx.db
.query('configuracoesAlmoxarifado')
.filter((q) => q.eq(q.field('ativo'), true))
.first();
if (!config) {
return {
estoqueMinimoPadrao: 10,
diasAntecedenciaAlerta: 7,
permitirEstoqueNegativo: false,
requerAprovacaoRequisicao: true,
rolesAprovacao: [],
emailAlertasAtivo: false,
emailsDestinatarios: [],
periodicidadeInventario: 30,
ultimoInventario: undefined,
ativo: true
};
}
return config;
}
});