128 lines
4.9 KiB
TypeScript
128 lines
4.9 KiB
TypeScript
import { NextResponse } from "next/server"
|
|
|
|
import { prisma } from "@/lib/prisma"
|
|
import { assertStaffSession } from "@/lib/auth-server"
|
|
import { isAdmin } from "@/lib/authz"
|
|
import { PrismaClientKnownRequestError } from "@prisma/client/runtime/library"
|
|
import { removeConvexCompany, syncConvexCompany } from "@/server/companies-sync"
|
|
|
|
export const runtime = "nodejs"
|
|
|
|
export async function PATCH(request: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
const session = await assertStaffSession()
|
|
if (!session) return NextResponse.json({ error: "Não autorizado" }, { status: 401 })
|
|
if (!isAdmin(session.user.role)) {
|
|
return NextResponse.json({ error: "Apenas administradores podem editar empresas" }, { status: 403 })
|
|
}
|
|
const { id } = await params
|
|
const raw = (await request.json()) as Partial<{
|
|
name: string
|
|
slug: string
|
|
cnpj: string | null
|
|
domain: string | null
|
|
phone: string | null
|
|
description: string | null
|
|
address: string | null
|
|
isAvulso: boolean
|
|
contractedHoursPerMonth: number | string | null
|
|
}>
|
|
|
|
const updates: Record<string, unknown> = {}
|
|
if (typeof raw.name === "string" && raw.name.trim()) updates.name = raw.name.trim()
|
|
if (typeof raw.slug === "string" && raw.slug.trim()) updates.slug = raw.slug.trim()
|
|
if ("cnpj" in raw) updates.cnpj = raw.cnpj ?? null
|
|
if ("domain" in raw) updates.domain = raw.domain ?? null
|
|
if ("phone" in raw) updates.phone = raw.phone ?? null
|
|
if ("description" in raw) updates.description = raw.description ?? null
|
|
if ("address" in raw) updates.address = raw.address ?? null
|
|
if ("isAvulso" in raw) updates.isAvulso = Boolean(raw.isAvulso)
|
|
if ("contractedHoursPerMonth" in raw) {
|
|
const v = raw.contractedHoursPerMonth
|
|
updates.contractedHoursPerMonth = typeof v === "number" ? v : v ? Number(v) : null
|
|
}
|
|
|
|
try {
|
|
// Tipos do Prisma podem estar desatualizados em relação ao schema nessa máquina/ambiente.
|
|
// Atualize o client quando possível; por ora liberamos o shape dinamicamente.
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
const company = await prisma.company.update({ where: { id }, data: updates as any })
|
|
|
|
if (company.provisioningCode) {
|
|
const synced = await syncConvexCompany({
|
|
tenantId: company.tenantId,
|
|
slug: company.slug,
|
|
name: company.name,
|
|
provisioningCode: company.provisioningCode,
|
|
})
|
|
if (!synced) {
|
|
console.warn("[admin.companies] Convex não configurado; atualização aplicada apenas no Prisma.")
|
|
}
|
|
}
|
|
|
|
return NextResponse.json({ company })
|
|
} catch (error) {
|
|
console.error("Failed to update company", error)
|
|
if (error instanceof PrismaClientKnownRequestError && error.code === "P2002") {
|
|
return NextResponse.json({ error: "Já existe uma empresa com este slug." }, { status: 409 })
|
|
}
|
|
return NextResponse.json({ error: "Falha ao atualizar empresa" }, { status: 500 })
|
|
}
|
|
}
|
|
|
|
export async function DELETE(_: Request, { params }: { params: Promise<{ id: string }> }) {
|
|
const session = await assertStaffSession()
|
|
if (!session) return NextResponse.json({ error: "Não autorizado" }, { status: 401 })
|
|
if (!isAdmin(session.user.role)) {
|
|
return NextResponse.json({ error: "Apenas administradores podem excluir empresas" }, { status: 403 })
|
|
}
|
|
const { id } = await params
|
|
|
|
const company = await prisma.company.findUnique({
|
|
where: { id },
|
|
select: { id: true, tenantId: true, name: true, slug: true },
|
|
})
|
|
|
|
if (!company) {
|
|
return NextResponse.json({ error: "Empresa não encontrada" }, { status: 404 })
|
|
}
|
|
|
|
if (company.tenantId !== (session.user.tenantId ?? company.tenantId)) {
|
|
return NextResponse.json({ error: "Acesso negado" }, { status: 403 })
|
|
}
|
|
|
|
try {
|
|
const result = await prisma.$transaction(async (tx) => {
|
|
const users = await tx.user.updateMany({
|
|
where: { companyId: company.id, tenantId: company.tenantId },
|
|
data: { companyId: null },
|
|
})
|
|
const tickets = await tx.ticket.updateMany({
|
|
where: { companyId: company.id, tenantId: company.tenantId },
|
|
data: { companyId: null },
|
|
})
|
|
await tx.company.delete({ where: { id: company.id } })
|
|
return { detachedUsers: users.count, detachedTickets: tickets.count }
|
|
})
|
|
|
|
if (company.slug) {
|
|
const removed = await removeConvexCompany({
|
|
tenantId: company.tenantId,
|
|
slug: company.slug,
|
|
})
|
|
if (!removed) {
|
|
console.warn("[admin.companies] Convex não configurado; empresa removida apenas no Prisma.")
|
|
}
|
|
}
|
|
|
|
return NextResponse.json({ ok: true, ...result })
|
|
} catch (error) {
|
|
if (error instanceof PrismaClientKnownRequestError && error.code === "P2003") {
|
|
return NextResponse.json(
|
|
{ error: "Não é possível remover esta empresa pois existem registros vinculados." },
|
|
{ status: 409 }
|
|
)
|
|
}
|
|
console.error("Failed to delete company", error)
|
|
return NextResponse.json({ error: "Falha ao excluir empresa" }, { status: 500 })
|
|
}
|
|
}
|