- Enhanced the employee registration form by adding checkboxes for "Salário Família" and "Imposto de Renda" for each dependent. - Updated the backend schema and mutations to include optional fields for salary family and income tax benefits. - Improved the handling of dependent data to accommodate the new fields, enhancing the overall functionality of the dependents management section.
463 lines
15 KiB
TypeScript
463 lines
15 KiB
TypeScript
import { v } from "convex/values";
|
|
import { query, mutation } from "./_generated/server";
|
|
import { internal } from "./_generated/api";
|
|
import { simboloTipo } from "./schema";
|
|
|
|
// Validadores para campos opcionais
|
|
const sexoValidator = v.optional(
|
|
v.union(v.literal("masculino"), v.literal("feminino"), v.literal("outro"))
|
|
);
|
|
const estadoCivilValidator = v.optional(
|
|
v.union(
|
|
v.literal("solteiro"),
|
|
v.literal("casado"),
|
|
v.literal("divorciado"),
|
|
v.literal("viuvo"),
|
|
v.literal("uniao_estavel")
|
|
)
|
|
);
|
|
const grauInstrucaoValidator = v.optional(
|
|
v.union(
|
|
v.literal("fundamental"),
|
|
v.literal("medio"),
|
|
v.literal("superior"),
|
|
v.literal("pos_graduacao"),
|
|
v.literal("mestrado"),
|
|
v.literal("doutorado")
|
|
)
|
|
);
|
|
const grupoSanguineoValidator = v.optional(
|
|
v.union(v.literal("A"), v.literal("B"), v.literal("AB"), v.literal("O"))
|
|
);
|
|
const fatorRHValidator = v.optional(
|
|
v.union(v.literal("positivo"), v.literal("negativo"))
|
|
);
|
|
const aposentadoValidator = v.optional(
|
|
v.union(v.literal("nao"), v.literal("funape_ipsep"), v.literal("inss"))
|
|
);
|
|
|
|
export const getAll = query({
|
|
args: {},
|
|
handler: async (ctx) => {
|
|
// Autorização: listar funcionários
|
|
await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, {
|
|
recurso: "funcionarios",
|
|
acao: "listar",
|
|
});
|
|
const funcionarios = await ctx.db.query("funcionarios").collect();
|
|
// Retornar apenas os campos necessários para listagem
|
|
return funcionarios.map((f) => ({
|
|
_id: f._id,
|
|
nome: f.nome,
|
|
matricula: f.matricula,
|
|
cpf: f.cpf,
|
|
rg: f.rg,
|
|
nascimento: f.nascimento,
|
|
email: f.email,
|
|
telefone: f.telefone,
|
|
endereco: f.endereco,
|
|
cep: f.cep,
|
|
cidade: f.cidade,
|
|
uf: f.uf,
|
|
simboloId: f.simboloId,
|
|
simboloTipo: f.simboloTipo,
|
|
admissaoData: f.admissaoData,
|
|
desligamentoData: f.desligamentoData,
|
|
descricaoCargo: f.descricaoCargo,
|
|
}));
|
|
},
|
|
});
|
|
|
|
export const getById = query({
|
|
args: { id: v.id("funcionarios") },
|
|
// Tipo inferido automaticamente pelo Convex
|
|
handler: async (ctx, args) => {
|
|
// Autorização: ver funcionário
|
|
await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, {
|
|
recurso: "funcionarios",
|
|
acao: "ver",
|
|
});
|
|
return await ctx.db.get(args.id);
|
|
},
|
|
});
|
|
|
|
export const create = mutation({
|
|
args: {
|
|
// Campos obrigatórios
|
|
nome: v.string(),
|
|
matricula: v.optional(v.string()),
|
|
simboloId: v.id("simbolos"),
|
|
nascimento: v.string(),
|
|
rg: v.string(),
|
|
cpf: v.string(),
|
|
endereco: v.string(),
|
|
cep: v.string(),
|
|
cidade: v.string(),
|
|
uf: v.string(),
|
|
telefone: v.string(),
|
|
email: v.string(),
|
|
admissaoData: v.optional(v.string()),
|
|
desligamentoData: v.optional(v.string()),
|
|
simboloTipo: simboloTipo,
|
|
|
|
// Dados Pessoais Adicionais
|
|
nomePai: v.optional(v.string()),
|
|
nomeMae: v.optional(v.string()),
|
|
naturalidade: v.optional(v.string()),
|
|
naturalidadeUF: v.optional(v.string()),
|
|
sexo: sexoValidator,
|
|
estadoCivil: estadoCivilValidator,
|
|
nacionalidade: v.optional(v.string()),
|
|
|
|
// Documentos Pessoais
|
|
rgOrgaoExpedidor: v.optional(v.string()),
|
|
rgDataEmissao: v.optional(v.string()),
|
|
carteiraProfissionalNumero: v.optional(v.string()),
|
|
carteiraProfissionalSerie: v.optional(v.string()),
|
|
carteiraProfissionalDataEmissao: v.optional(v.string()),
|
|
reservistaNumero: v.optional(v.string()),
|
|
reservistaSerie: v.optional(v.string()),
|
|
tituloEleitorNumero: v.optional(v.string()),
|
|
tituloEleitorZona: v.optional(v.string()),
|
|
tituloEleitorSecao: v.optional(v.string()),
|
|
pisNumero: v.optional(v.string()),
|
|
|
|
// Formação e Saúde
|
|
grauInstrucao: grauInstrucaoValidator,
|
|
formacao: v.optional(v.string()),
|
|
formacaoRegistro: v.optional(v.string()),
|
|
grupoSanguineo: grupoSanguineoValidator,
|
|
fatorRH: fatorRHValidator,
|
|
|
|
// Cargo e Vínculo
|
|
descricaoCargo: v.optional(v.string()),
|
|
nomeacaoPortaria: v.optional(v.string()),
|
|
nomeacaoData: v.optional(v.string()),
|
|
nomeacaoDOE: v.optional(v.string()),
|
|
pertenceOrgaoPublico: v.optional(v.boolean()),
|
|
orgaoOrigem: v.optional(v.string()),
|
|
aposentado: aposentadoValidator,
|
|
|
|
// Dados Bancários
|
|
contaBradescoNumero: v.optional(v.string()),
|
|
contaBradescoDV: v.optional(v.string()),
|
|
contaBradescoAgencia: v.optional(v.string()),
|
|
|
|
// Documentos Anexos (Storage IDs)
|
|
certidaoAntecedentesPF: v.optional(v.id("_storage")),
|
|
certidaoAntecedentesJFPE: v.optional(v.id("_storage")),
|
|
certidaoAntecedentesSDS: v.optional(v.id("_storage")),
|
|
certidaoAntecedentesTJPE: v.optional(v.id("_storage")),
|
|
certidaoImprobidade: v.optional(v.id("_storage")),
|
|
rgFrente: v.optional(v.id("_storage")),
|
|
rgVerso: v.optional(v.id("_storage")),
|
|
cpfFrente: v.optional(v.id("_storage")),
|
|
cpfVerso: v.optional(v.id("_storage")),
|
|
situacaoCadastralCPF: v.optional(v.id("_storage")),
|
|
tituloEleitorFrente: v.optional(v.id("_storage")),
|
|
tituloEleitorVerso: v.optional(v.id("_storage")),
|
|
comprovanteVotacao: v.optional(v.id("_storage")),
|
|
carteiraProfissionalFrente: v.optional(v.id("_storage")),
|
|
carteiraProfissionalVerso: v.optional(v.id("_storage")),
|
|
comprovantePIS: v.optional(v.id("_storage")),
|
|
certidaoRegistroCivil: v.optional(v.id("_storage")),
|
|
certidaoNascimentoDependentes: v.optional(v.id("_storage")),
|
|
cpfDependentes: v.optional(v.id("_storage")),
|
|
reservistaDoc: v.optional(v.id("_storage")),
|
|
comprovanteEscolaridade: v.optional(v.id("_storage")),
|
|
comprovanteResidencia: v.optional(v.id("_storage")),
|
|
comprovanteContaBradesco: v.optional(v.id("_storage")),
|
|
|
|
// Declarações (Storage IDs)
|
|
declaracaoAcumulacaoCargo: v.optional(v.id("_storage")),
|
|
declaracaoDependentesIR: v.optional(v.id("_storage")),
|
|
declaracaoIdoneidade: v.optional(v.id("_storage")),
|
|
termoNepotismo: v.optional(v.id("_storage")),
|
|
termoOpcaoRemuneracao: v.optional(v.id("_storage")),
|
|
// Dependentes (opcional)
|
|
dependentes: v.optional(
|
|
v.array(
|
|
v.object({
|
|
parentesco: v.union(
|
|
v.literal("filho"),
|
|
v.literal("filha"),
|
|
v.literal("conjuge"),
|
|
v.literal("outro")
|
|
),
|
|
nome: v.string(),
|
|
cpf: v.string(),
|
|
nascimento: v.string(),
|
|
documentoId: v.optional(v.id("_storage")),
|
|
salarioFamilia: v.optional(v.boolean()),
|
|
impostoRenda: v.optional(v.boolean()),
|
|
})
|
|
)
|
|
),
|
|
},
|
|
returns: v.id("funcionarios"),
|
|
handler: async (ctx, args) => {
|
|
// Autorização: criar
|
|
await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, {
|
|
recurso: "funcionarios",
|
|
acao: "criar",
|
|
});
|
|
// Unicidade: CPF
|
|
const cpfExists = await ctx.db
|
|
.query("funcionarios")
|
|
.withIndex("by_cpf", (q) => q.eq("cpf", args.cpf))
|
|
.unique();
|
|
if (cpfExists) {
|
|
throw new Error("CPF já cadastrado");
|
|
}
|
|
|
|
// Unicidade: Matrícula (apenas se fornecida)
|
|
if (args.matricula) {
|
|
const matriculaExists = await ctx.db
|
|
.query("funcionarios")
|
|
.withIndex("by_matricula", (q) => q.eq("matricula", args.matricula))
|
|
.unique();
|
|
if (matriculaExists) {
|
|
throw new Error(
|
|
"Já existe um funcionário com esta matrícula. Por favor, use outra ou deixe em branco."
|
|
);
|
|
}
|
|
}
|
|
|
|
const novoFuncionarioId = await ctx.db.insert("funcionarios", args);
|
|
return novoFuncionarioId;
|
|
},
|
|
});
|
|
|
|
export const update = mutation({
|
|
args: {
|
|
id: v.id("funcionarios"),
|
|
// Campos obrigatórios
|
|
nome: v.string(),
|
|
matricula: v.optional(v.string()),
|
|
simboloId: v.id("simbolos"),
|
|
nascimento: v.string(),
|
|
rg: v.string(),
|
|
cpf: v.string(),
|
|
endereco: v.string(),
|
|
cep: v.string(),
|
|
cidade: v.string(),
|
|
uf: v.string(),
|
|
telefone: v.string(),
|
|
email: v.string(),
|
|
admissaoData: v.optional(v.string()),
|
|
desligamentoData: v.optional(v.string()),
|
|
simboloTipo: simboloTipo,
|
|
|
|
// Dados Pessoais Adicionais
|
|
nomePai: v.optional(v.string()),
|
|
nomeMae: v.optional(v.string()),
|
|
naturalidade: v.optional(v.string()),
|
|
naturalidadeUF: v.optional(v.string()),
|
|
sexo: sexoValidator,
|
|
estadoCivil: estadoCivilValidator,
|
|
nacionalidade: v.optional(v.string()),
|
|
|
|
// Documentos Pessoais
|
|
rgOrgaoExpedidor: v.optional(v.string()),
|
|
rgDataEmissao: v.optional(v.string()),
|
|
carteiraProfissionalNumero: v.optional(v.string()),
|
|
carteiraProfissionalSerie: v.optional(v.string()),
|
|
carteiraProfissionalDataEmissao: v.optional(v.string()),
|
|
reservistaNumero: v.optional(v.string()),
|
|
reservistaSerie: v.optional(v.string()),
|
|
tituloEleitorNumero: v.optional(v.string()),
|
|
tituloEleitorZona: v.optional(v.string()),
|
|
tituloEleitorSecao: v.optional(v.string()),
|
|
pisNumero: v.optional(v.string()),
|
|
|
|
// Formação e Saúde
|
|
grauInstrucao: grauInstrucaoValidator,
|
|
formacao: v.optional(v.string()),
|
|
formacaoRegistro: v.optional(v.string()),
|
|
grupoSanguineo: grupoSanguineoValidator,
|
|
fatorRH: fatorRHValidator,
|
|
|
|
// Cargo e Vínculo
|
|
descricaoCargo: v.optional(v.string()),
|
|
nomeacaoPortaria: v.optional(v.string()),
|
|
nomeacaoData: v.optional(v.string()),
|
|
nomeacaoDOE: v.optional(v.string()),
|
|
pertenceOrgaoPublico: v.optional(v.boolean()),
|
|
orgaoOrigem: v.optional(v.string()),
|
|
aposentado: aposentadoValidator,
|
|
|
|
// Dados Bancários
|
|
contaBradescoNumero: v.optional(v.string()),
|
|
contaBradescoDV: v.optional(v.string()),
|
|
contaBradescoAgencia: v.optional(v.string()),
|
|
|
|
// Documentos Anexos (Storage IDs)
|
|
certidaoAntecedentesPF: v.optional(v.id("_storage")),
|
|
certidaoAntecedentesJFPE: v.optional(v.id("_storage")),
|
|
certidaoAntecedentesSDS: v.optional(v.id("_storage")),
|
|
certidaoAntecedentesTJPE: v.optional(v.id("_storage")),
|
|
certidaoImprobidade: v.optional(v.id("_storage")),
|
|
rgFrente: v.optional(v.id("_storage")),
|
|
rgVerso: v.optional(v.id("_storage")),
|
|
cpfFrente: v.optional(v.id("_storage")),
|
|
cpfVerso: v.optional(v.id("_storage")),
|
|
situacaoCadastralCPF: v.optional(v.id("_storage")),
|
|
tituloEleitorFrente: v.optional(v.id("_storage")),
|
|
tituloEleitorVerso: v.optional(v.id("_storage")),
|
|
comprovanteVotacao: v.optional(v.id("_storage")),
|
|
carteiraProfissionalFrente: v.optional(v.id("_storage")),
|
|
carteiraProfissionalVerso: v.optional(v.id("_storage")),
|
|
comprovantePIS: v.optional(v.id("_storage")),
|
|
certidaoRegistroCivil: v.optional(v.id("_storage")),
|
|
certidaoNascimentoDependentes: v.optional(v.id("_storage")),
|
|
cpfDependentes: v.optional(v.id("_storage")),
|
|
reservistaDoc: v.optional(v.id("_storage")),
|
|
comprovanteEscolaridade: v.optional(v.id("_storage")),
|
|
comprovanteResidencia: v.optional(v.id("_storage")),
|
|
comprovanteContaBradesco: v.optional(v.id("_storage")),
|
|
|
|
// Declarações (Storage IDs)
|
|
declaracaoAcumulacaoCargo: v.optional(v.id("_storage")),
|
|
declaracaoDependentesIR: v.optional(v.id("_storage")),
|
|
declaracaoIdoneidade: v.optional(v.id("_storage")),
|
|
termoNepotismo: v.optional(v.id("_storage")),
|
|
termoOpcaoRemuneracao: v.optional(v.id("_storage")),
|
|
// Dependentes (opcional)
|
|
dependentes: v.optional(
|
|
v.array(
|
|
v.object({
|
|
parentesco: v.union(
|
|
v.literal("filho"),
|
|
v.literal("filha"),
|
|
v.literal("conjuge"),
|
|
v.literal("outro")
|
|
),
|
|
nome: v.string(),
|
|
cpf: v.string(),
|
|
nascimento: v.string(),
|
|
documentoId: v.optional(v.id("_storage")),
|
|
salarioFamilia: v.optional(v.boolean()),
|
|
impostoRenda: v.optional(v.boolean()),
|
|
})
|
|
)
|
|
),
|
|
},
|
|
returns: v.null(),
|
|
handler: async (ctx, args) => {
|
|
// Autorização: editar
|
|
await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, {
|
|
recurso: "funcionarios",
|
|
acao: "editar",
|
|
});
|
|
// Unicidade: CPF (excluindo o próprio registro)
|
|
const cpfExists = await ctx.db
|
|
.query("funcionarios")
|
|
.withIndex("by_cpf", (q) => q.eq("cpf", args.cpf))
|
|
.unique();
|
|
if (cpfExists && cpfExists._id !== args.id) {
|
|
throw new Error("CPF já cadastrado");
|
|
}
|
|
|
|
// Unicidade: Matrícula (apenas se fornecida, excluindo o próprio registro)
|
|
if (args.matricula) {
|
|
const matriculaExists = await ctx.db
|
|
.query("funcionarios")
|
|
.withIndex("by_matricula", (q) => q.eq("matricula", args.matricula))
|
|
.unique();
|
|
if (matriculaExists && matriculaExists._id !== args.id) {
|
|
throw new Error(
|
|
"Já existe um funcionário com esta matrícula. Por favor, use outra ou deixe em branco."
|
|
);
|
|
}
|
|
}
|
|
|
|
const { id, ...updateData } = args;
|
|
await ctx.db.patch(id, updateData);
|
|
return null;
|
|
},
|
|
});
|
|
|
|
export const remove = mutation({
|
|
args: { id: v.id("funcionarios") },
|
|
returns: v.null(),
|
|
handler: async (ctx, args) => {
|
|
// Autorização: excluir
|
|
await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, {
|
|
recurso: "funcionarios",
|
|
acao: "excluir",
|
|
});
|
|
// TODO: Talvez queiramos também remover os arquivos do storage
|
|
await ctx.db.delete(args.id);
|
|
return null;
|
|
},
|
|
});
|
|
|
|
// Query para obter ficha completa para impressão
|
|
export const getFichaCompleta = query({
|
|
args: { id: v.id("funcionarios") },
|
|
// Tipo inferido automaticamente pelo Convex
|
|
handler: async (ctx, args) => {
|
|
await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, {
|
|
recurso: "funcionarios",
|
|
acao: "ver",
|
|
});
|
|
const funcionario = await ctx.db.get(args.id);
|
|
if (!funcionario) {
|
|
return null;
|
|
}
|
|
|
|
// Buscar informações do símbolo
|
|
const simbolo = await ctx.db.get(funcionario.simboloId);
|
|
|
|
// Buscar cursos do funcionário
|
|
const cursos = await ctx.db
|
|
.query("cursos")
|
|
.withIndex("by_funcionario", (q) => q.eq("funcionarioId", args.id))
|
|
.collect();
|
|
|
|
// Buscar URLs dos certificados
|
|
const cursosComUrls = await Promise.all(
|
|
cursos.map(async (curso) => {
|
|
let certificadoUrl = null;
|
|
if (curso.certificadoId) {
|
|
certificadoUrl = await ctx.storage.getUrl(curso.certificadoId);
|
|
}
|
|
return {
|
|
...curso,
|
|
certificadoUrl,
|
|
};
|
|
})
|
|
);
|
|
|
|
return {
|
|
...funcionario,
|
|
simbolo: simbolo
|
|
? {
|
|
nome: simbolo.nome,
|
|
descricao: simbolo.descricao,
|
|
tipo: simbolo.tipo,
|
|
vencValor: simbolo.vencValor,
|
|
repValor: simbolo.repValor,
|
|
valor: simbolo.valor,
|
|
}
|
|
: null,
|
|
cursos: cursosComUrls,
|
|
};
|
|
},
|
|
});
|
|
|
|
// Mutation: Configurar gestor (apenas para TI_MASTER)
|
|
export const configurarGestor = mutation({
|
|
args: {
|
|
funcionarioId: v.id("funcionarios"),
|
|
gestorId: v.optional(v.id("usuarios")),
|
|
},
|
|
returns: v.null(),
|
|
handler: async (ctx, args) => {
|
|
await ctx.db.patch(args.funcionarioId, {
|
|
gestorId: args.gestorId,
|
|
});
|
|
return null;
|
|
},
|
|
});
|