import { v } from 'convex/values'; import { mutation, query } from './_generated/server'; import { internal } from './_generated/api'; import { getCurrentUserFunction } from './auth'; import type { Id } from './_generated/dataModel'; export const list = query({ args: { query: v.optional(v.string()) }, handler: async (ctx, args) => { await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, { recurso: 'empresas', acao: 'listar' }); const empresas = await ctx.db.query('empresas').collect(); const term = args.query?.trim(); if (!term) return empresas; const termLower = term.toLowerCase(); const termDigits = term.replace(/\D/g, ''); return empresas.filter((empresa) => { const razao = (empresa.razao_social || '').toLowerCase(); const fantasia = (empresa.nome_fantasia || '').toLowerCase(); const cnpjRaw = empresa.cnpj || ''; const cnpjLower = cnpjRaw.toLowerCase(); const cnpjDigits = cnpjRaw.replace(/\D/g, ''); const matchNome = razao.includes(termLower) || fantasia.includes(termLower); const matchCnpj = termDigits ? cnpjDigits.includes(termDigits) : cnpjLower.includes(termLower); return matchNome || matchCnpj; }); } }); export const getById = query({ args: { id: v.id('empresas') }, handler: async (ctx, args) => { await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, { recurso: 'empresas', acao: 'ver' }); const empresa = await ctx.db.get(args.id); if (!empresa) { return null; } const contatos = await ctx.db .query('contatosEmpresa') .withIndex('by_empresa', (q) => q.eq('empresaId', args.id)) .collect(); const endereco = empresa.enderecoId ? await ctx.db.get(empresa.enderecoId as Id<'enderecos'>) : null; return { ...empresa, endereco, contatos }; } }); const contatoInput = v.object({ _id: v.optional(v.id('contatosEmpresa')), empresaId: v.optional(v.id('empresas')), nome: v.string(), funcao: v.string(), email: v.string(), telefone: v.string(), adicionadoPor: v.optional(v.id('usuarios')), descricao: v.optional(v.string()), _deleted: v.optional(v.boolean()) }); const enderecoInput = v.object({ cep: v.string(), logradouro: v.string(), numero: v.string(), complemento: v.optional(v.string()), bairro: v.string(), cidade: v.string(), uf: v.string() }); export const create = mutation({ args: { razao_social: v.string(), nome_fantasia: v.optional(v.string()), cnpj: v.string(), telefone: v.string(), email: v.string(), descricao: v.optional(v.string()), endereco: v.optional(enderecoInput), contatos: v.optional(v.array(contatoInput)) }, returns: v.id('empresas'), handler: async (ctx, args) => { const usuarioAtual = await getCurrentUserFunction(ctx); if (!usuarioAtual) { throw new Error('Usuário não autenticado.'); } await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, { recurso: 'empresas', acao: 'criar' }); const cnpjExistente = await ctx.db .query('empresas') .withIndex('by_cnpj', (q) => q.eq('cnpj', args.cnpj)) .unique(); if (cnpjExistente) { throw new Error('Já existe uma empresa cadastrada com este CNPJ.'); } let enderecoId: Id<'enderecos'> | undefined; if (args.endereco) { enderecoId = await ctx.db.insert('enderecos', { cep: args.endereco.cep, logradouro: args.endereco.logradouro, numero: args.endereco.numero, complemento: args.endereco.complemento, bairro: args.endereco.bairro, cidade: args.endereco.cidade, uf: args.endereco.uf, criadoPor: usuarioAtual._id, atualizadoPor: usuarioAtual._id }); } const empresaDoc: { razao_social: string; nome_fantasia?: string; cnpj: string; telefone: string; email: string; descricao?: string; enderecoId?: Id<'enderecos'>; criadoPor: Id<'usuarios'>; } = { razao_social: args.razao_social, cnpj: args.cnpj, telefone: args.telefone, email: args.email, criadoPor: usuarioAtual._id }; if (args.nome_fantasia !== undefined) { empresaDoc.nome_fantasia = args.nome_fantasia; } if (args.descricao !== undefined) { empresaDoc.descricao = args.descricao; } if (enderecoId) { empresaDoc.enderecoId = enderecoId; } const empresaId = await ctx.db.insert('empresas', empresaDoc); if (args.contatos && args.contatos.length > 0) { for (const contato of args.contatos) { await ctx.db.insert('contatosEmpresa', { empresaId, nome: contato.nome, funcao: contato.funcao, email: contato.email, telefone: contato.telefone, adicionadoPor: usuarioAtual._id, descricao: contato.descricao }); } } return empresaId; } }); export const update = mutation({ args: { id: v.id('empresas'), razao_social: v.string(), nome_fantasia: v.optional(v.string()), cnpj: v.string(), telefone: v.string(), email: v.string(), descricao: v.optional(v.string()), endereco: v.optional(enderecoInput), contatos: v.optional(v.array(contatoInput)) }, returns: v.null(), handler: async (ctx, args) => { await ctx.runQuery(internal.permissoesAcoes.assertPermissaoAcaoAtual, { recurso: 'empresas', acao: 'editar' }); const cnpjExistente = await ctx.db .query('empresas') .withIndex('by_cnpj', (q) => q.eq('cnpj', args.cnpj)) .unique(); if (cnpjExistente && cnpjExistente._id !== args.id) { throw new Error('Já existe uma empresa cadastrada com este CNPJ.'); } const empresa = await ctx.db.get(args.id); if (!empresa) { throw new Error('Empresa não encontrada.'); } if (args.endereco) { if (empresa.enderecoId) { const usuarioAtual = await getCurrentUserFunction(ctx); await ctx.db.patch(empresa.enderecoId as Id<'enderecos'>, { cep: args.endereco.cep, logradouro: args.endereco.logradouro, numero: args.endereco.numero, complemento: args.endereco.complemento, bairro: args.endereco.bairro, cidade: args.endereco.cidade, uf: args.endereco.uf, atualizadoPor: usuarioAtual?._id }); } else { const usuarioAtual = await getCurrentUserFunction(ctx); if (!usuarioAtual) { throw new Error('Usuário não autenticado.'); } const novoEnderecoId: Id<'enderecos'> = await ctx.db.insert('enderecos', { cep: args.endereco.cep, logradouro: args.endereco.logradouro, numero: args.endereco.numero, complemento: args.endereco.complemento, bairro: args.endereco.bairro, cidade: args.endereco.cidade, uf: args.endereco.uf, criadoPor: usuarioAtual._id, atualizadoPor: usuarioAtual._id }); await ctx.db.patch(args.id, { enderecoId: novoEnderecoId }); } } const patchDoc: { razao_social: string; nome_fantasia?: string; cnpj: string; telefone: string; email: string; descricao?: string; } = { razao_social: args.razao_social, cnpj: args.cnpj, telefone: args.telefone, email: args.email }; if (args.nome_fantasia !== undefined) { patchDoc.nome_fantasia = args.nome_fantasia; } if (args.descricao !== undefined) { patchDoc.descricao = args.descricao; } await ctx.db.patch(args.id, patchDoc); if (!args.contatos) { return null; } for (const contato of args.contatos) { if (contato._id && contato._deleted) { await ctx.db.delete(contato._id); } else if (contato._id) { await ctx.db.patch(contato._id, { nome: contato.nome, funcao: contato.funcao, email: contato.email, telefone: contato.telefone, descricao: contato.descricao }); } else if (!contato._deleted) { const usuarioAtual = await getCurrentUserFunction(ctx); if (!usuarioAtual) { throw new Error('Usuário não autenticado.'); } await ctx.db.insert('contatosEmpresa', { empresaId: args.id, nome: contato.nome, funcao: contato.funcao, email: contato.email, telefone: contato.telefone, adicionadoPor: usuarioAtual._id, descricao: contato.descricao }); } } return null; } });