feat: allow company deletion by detaching dependents
This commit is contained in:
parent
2980885bf8
commit
7951bc25a3
3 changed files with 32 additions and 21 deletions
|
|
@ -23,6 +23,7 @@ Resultado: front/back sobem com o novo código sem editar o stack a cada release
|
||||||
- Mount fixo: `/home/renan/apps/sistema.current:/app` (não interpolar APP_DIR).
|
- Mount fixo: `/home/renan/apps/sistema.current:/app` (não interpolar APP_DIR).
|
||||||
- Comando inline (sem script), com migrations na subida:
|
- Comando inline (sem script), com migrations na subida:
|
||||||
- `command: ["bash","-lc","corepack enable && corepack prepare pnpm@9 --activate && pnpm exec prisma migrate deploy && pnpm start -p 3000"]`
|
- `command: ["bash","-lc","corepack enable && corepack prepare pnpm@9 --activate && pnpm exec prisma migrate deploy && pnpm start -p 3000"]`
|
||||||
|
- **Se você optar por usar `/app/scripts/start-web.sh`** (como no workflow atual), ele já garante `pnpm@9` via Corepack/NPM antes de rodar Prisma/Next. Certifique-se de copiar esse arquivo para o build publicado; sem ele, a task cai com `pnpm: command not found`.
|
||||||
- Env obrigatórias (URLs válidas):
|
- Env obrigatórias (URLs válidas):
|
||||||
- `DATABASE_URL=file:/app/data/db.sqlite`
|
- `DATABASE_URL=file:/app/data/db.sqlite`
|
||||||
- `NEXT_PUBLIC_CONVEX_URL=http://sistema_convex_backend:3210`
|
- `NEXT_PUBLIC_CONVEX_URL=http://sistema_convex_backend:3210`
|
||||||
|
|
@ -121,4 +122,3 @@ docker service scale sistema_web=1
|
||||||
|
|
||||||
- Como o stack monta `/home/renan/apps/sistema.current`, um novo release exige apenas atualizar o symlink e forçar a task. O `stack.yml` só precisa ser redeployado quando você altera labels/envs/serviços.
|
- Como o stack monta `/home/renan/apps/sistema.current`, um novo release exige apenas atualizar o symlink e forçar a task. O `stack.yml` só precisa ser redeployado quando você altera labels/envs/serviços.
|
||||||
- Se a UI parecer não mudar, valide o mount/args via inspect, confira logs da task atual e force hard‑reload no navegador.
|
- Se a UI parecer não mudar, valide o mount/args via inspect, confira logs da task atual e force hard‑reload no navegador.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -77,23 +77,20 @@ export async function DELETE(_: Request, { params }: { params: Promise<{ id: str
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Pré‑checagem para evitar 500 por FK: conta vínculos antes
|
const result = await prisma.$transaction(async (tx) => {
|
||||||
const [usersCount, ticketsCount] = await Promise.all([
|
const users = await tx.user.updateMany({
|
||||||
prisma.user.count({ where: { companyId: company.id } }),
|
where: { companyId: company.id, tenantId: company.tenantId },
|
||||||
prisma.ticket.count({ where: { companyId: company.id } }),
|
data: { companyId: null },
|
||||||
])
|
})
|
||||||
if (usersCount > 0 || ticketsCount > 0) {
|
const tickets = await tx.ticket.updateMany({
|
||||||
return NextResponse.json(
|
where: { companyId: company.id, tenantId: company.tenantId },
|
||||||
{
|
data: { companyId: null },
|
||||||
error: "Não é possível remover esta empresa pois existem registros vinculados.",
|
})
|
||||||
details: { users: usersCount, tickets: ticketsCount },
|
await tx.company.delete({ where: { id: company.id } })
|
||||||
},
|
return { detachedUsers: users.count, detachedTickets: tickets.count }
|
||||||
{ status: 409 }
|
})
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
await prisma.company.delete({ where: { id: company.id } })
|
return NextResponse.json({ ok: true, ...result })
|
||||||
return NextResponse.json({ ok: true })
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
if (error instanceof PrismaClientKnownRequestError && error.code === "P2003") {
|
if (error instanceof PrismaClientKnownRequestError && error.code === "P2003") {
|
||||||
return NextResponse.json(
|
return NextResponse.json(
|
||||||
|
|
|
||||||
|
|
@ -184,11 +184,25 @@ export function AdminCompaniesManager({ initialCompanies }: { initialCompanies:
|
||||||
method: "DELETE",
|
method: "DELETE",
|
||||||
credentials: "include",
|
credentials: "include",
|
||||||
})
|
})
|
||||||
if (!response.ok) {
|
const data = (await response.json().catch(() => ({}))) as {
|
||||||
const data = await response.json().catch(() => ({}))
|
error?: string
|
||||||
throw new Error(data.error ?? "Falha ao excluir empresa")
|
detachedUsers?: number
|
||||||
|
detachedTickets?: number
|
||||||
}
|
}
|
||||||
toast.success("Empresa removida")
|
if (!response.ok) {
|
||||||
|
throw new Error(data?.error ?? "Falha ao excluir empresa")
|
||||||
|
}
|
||||||
|
const detachedUsers = data?.detachedUsers ?? 0
|
||||||
|
const detachedTickets = data?.detachedTickets ?? 0
|
||||||
|
const details: string[] = []
|
||||||
|
if (detachedUsers > 0) {
|
||||||
|
details.push(`${detachedUsers} usuário${detachedUsers > 1 ? "s" : ""} desvinculado${detachedUsers > 1 ? "s" : ""}`)
|
||||||
|
}
|
||||||
|
if (detachedTickets > 0) {
|
||||||
|
details.push(`${detachedTickets} ticket${detachedTickets > 1 ? "s" : ""} atualizado${detachedTickets > 1 ? "s" : ""}`)
|
||||||
|
}
|
||||||
|
const successMessage = details.length > 0 ? `Empresa removida (${details.join(", ")})` : "Empresa removida"
|
||||||
|
toast.success(successMessage)
|
||||||
if (editingId === deleteId) {
|
if (editingId === deleteId) {
|
||||||
resetForm()
|
resetForm()
|
||||||
setEditingId(null)
|
setEditingId(null)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue