feat: adiciona SLA por empresa e modal de exclusao de automacoes
Some checks failed
CI/CD Web + Desktop / Detect changes (push) Successful in 8s
CI/CD Web + Desktop / Deploy (VPS Linux) (push) Successful in 3m45s
Quality Checks / Lint, Test and Build (push) Successful in 3m58s
CI/CD Web + Desktop / Deploy Convex functions (push) Failing after 1m17s

## SLA por Empresa
- Adiciona tabela companySlaSettings no schema
- Cria convex/companySlas.ts com queries e mutations
- Modifica resolveTicketSlaSnapshot para verificar SLA da empresa primeiro
- Fallback: empresa > categoria > padrao

## Modal de Exclusao de Automacoes
- Substitui confirm() nativo por Dialog gracioso
- Segue padrao do delete-ticket-dialog

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
rever-tecnologia 2025-12-17 18:44:05 -03:00
parent b3fcbcc682
commit 33f0cc2e13
4 changed files with 404 additions and 22 deletions

View file

@ -272,25 +272,74 @@ async function resolveTicketSlaSnapshot(
ctx: AnyCtx,
tenantId: string,
category: Doc<"ticketCategories"> | null,
priority: string
priority: string,
companyId?: Id<"companies"> | null
): Promise<TicketSlaSnapshot | null> {
if (!category) {
return null;
}
const normalizedPriority = priority.trim().toUpperCase();
const rule =
(await ctx.db
.query("categorySlaSettings")
.withIndex("by_tenant_category_priority", (q) =>
q.eq("tenantId", tenantId).eq("categoryId", category._id).eq("priority", normalizedPriority)
// 1. Primeiro, tenta buscar SLA específico da empresa (se companyId foi informado)
let rule: {
responseTargetMinutes?: number;
responseMode?: string;
solutionTargetMinutes?: number;
solutionMode?: string;
alertThreshold?: number;
pauseStatuses?: string[];
} | null = null;
if (companyId) {
// Tenta: empresa + categoria + prioridade
rule = await ctx.db
.query("companySlaSettings")
.withIndex("by_tenant_company_category_priority", (q) =>
q.eq("tenantId", tenantId).eq("companyId", companyId).eq("categoryId", category._id).eq("priority", normalizedPriority)
)
.first()) ??
(await ctx.db
.query("categorySlaSettings")
.withIndex("by_tenant_category_priority", (q) =>
q.eq("tenantId", tenantId).eq("categoryId", category._id).eq("priority", "DEFAULT")
)
.first());
.first();
// Fallback: empresa + categoria + DEFAULT
if (!rule) {
rule = await ctx.db
.query("companySlaSettings")
.withIndex("by_tenant_company_category_priority", (q) =>
q.eq("tenantId", tenantId).eq("companyId", companyId).eq("categoryId", category._id).eq("priority", "DEFAULT")
)
.first();
}
// Fallback: empresa + todas categorias (categoryId null) + prioridade
if (!rule) {
const allCategoriesRules = await ctx.db
.query("companySlaSettings")
.withIndex("by_tenant_company", (q) => q.eq("tenantId", tenantId).eq("companyId", companyId))
.filter((q) => q.eq(q.field("categoryId"), undefined))
.take(10);
rule = allCategoriesRules.find((r) => r.priority === normalizedPriority) ??
allCategoriesRules.find((r) => r.priority === "DEFAULT") ??
null;
}
}
// 2. Se não encontrou SLA da empresa, usa SLA da categoria (comportamento padrão)
if (!rule) {
rule =
(await ctx.db
.query("categorySlaSettings")
.withIndex("by_tenant_category_priority", (q) =>
q.eq("tenantId", tenantId).eq("categoryId", category._id).eq("priority", normalizedPriority)
)
.first()) ??
(await ctx.db
.query("categorySlaSettings")
.withIndex("by_tenant_category_priority", (q) =>
q.eq("tenantId", tenantId).eq("categoryId", category._id).eq("priority", "DEFAULT")
)
.first());
}
if (!rule) {
return null;
}
@ -2325,7 +2374,7 @@ export const create = mutation({
avatarUrl: requester.avatarUrl ?? undefined,
teams: requester.teams ?? undefined,
}
const slaSnapshot = await resolveTicketSlaSnapshot(ctx, args.tenantId, category as Doc<"ticketCategories"> | null, args.priority)
// Resolve a empresa primeiro para poder verificar SLA específico
let companyDoc = requester.companyId ? (await ctx.db.get(requester.companyId)) : null
if (!companyDoc && machineDoc?.companyId) {
const candidateCompany = await ctx.db.get(machineDoc.companyId)
@ -2337,6 +2386,8 @@ export const create = mutation({
? { name: companyDoc.name, slug: companyDoc.slug, isAvulso: companyDoc.isAvulso ?? undefined }
: undefined
const resolvedCompanyId = companyDoc?._id ?? requester.companyId ?? undefined
// Resolve SLA passando companyId para verificar regras específicas da empresa
const slaSnapshot = await resolveTicketSlaSnapshot(ctx, args.tenantId, category as Doc<"ticketCategories"> | null, args.priority, resolvedCompanyId)
let checklist = manualChecklist
for (const templateId of args.checklistTemplateIds ?? []) {