mirror of
https://github.com/melgarafael/DeskcommCRM.git
synced 2026-10-02 01:28:34 +08:00
fix(suspensao): reativar só fala de cobrança com empresa suspensa de fato
O pré-check do 409 suspensao_de_cobranca perguntava "a empresa está parada?" em vez de "está suspensa?". Uma empresa redigida pela LGPD é parada e guarda o tipo residual 'cobranca' (o redact não limpa a coluna), e o admin receberia a instrução errada de negociar pagamento. Agora a régua é status = 'suspended'; a função responde nao_suspensa como sempre. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
41da980e6a
commit
d0aaa8761f
@@ -76,6 +76,17 @@ describe("POST /admin/tenants/[id]/reactivate", () => {
|
||||
expect(h.rpc).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("org REDIGIDA com tipo residual 'cobranca' → não é 409 de cobrança (a função responde)", async () => {
|
||||
// O lgpd-redact-worker troca status para 'redacted' sem limpar o tipo:
|
||||
// parada, mas não suspensa — negociar pagamento seria instrução errada.
|
||||
h.org = { id: TENANT, slug: "acme", status: "redacted", suspended_kind: "cobranca" };
|
||||
h.rpc.mockResolvedValue({ data: { changed: false, motivo: "nao_suspensa" }, error: null });
|
||||
const res = await POST(pedido({ reason: MOTIVO }), ctx);
|
||||
expect(res.status).toBe(200);
|
||||
expect((await res.json()).data).toEqual({ changed: false, motivo: "nao_suspensa" });
|
||||
expect(h.rpc).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it("administrativa reativa pela função com kind exigido e audita com o motivo", async () => {
|
||||
const res = await POST(pedido({ reason: MOTIVO }), ctx);
|
||||
expect(res.status).toBe(200);
|
||||
|
||||
@@ -17,7 +17,7 @@ import {
|
||||
requirePlatformAdminEscrita,
|
||||
type PlatformAdminContext,
|
||||
} from "@/lib/auth/requirePlatformAdmin";
|
||||
import { ehOperante, type TipoDeSuspensao } from "@/lib/organizacao/operante";
|
||||
import { type TipoDeSuspensao } from "@/lib/organizacao/operante";
|
||||
import { createAdminClient } from "@/lib/supabase/admin";
|
||||
import { ok, fail } from "@/lib/api/wrappers";
|
||||
import { audit } from "@/lib/audit";
|
||||
@@ -67,9 +67,10 @@ export async function POST(
|
||||
return fail("not_found", "Tenant not found", 404, { requestId });
|
||||
}
|
||||
|
||||
// `suspended_kind` só significa algo com a org parada (operante.ts). A função
|
||||
// também recusa o kind divergente; aqui é para a mensagem ter nome.
|
||||
if (!ehOperante(org.status) && org.suspended_kind === KIND_DE_COBRANCA) {
|
||||
// `suspended_kind` só significa algo com status='suspended' (operante.ts): a
|
||||
// org redigida é parada e guarda o tipo residual, e não se negocia pagamento
|
||||
// com ela. A função também recusa o kind divergente; aqui é para a mensagem ter nome.
|
||||
if (org.status === "suspended" && org.suspended_kind === KIND_DE_COBRANCA) {
|
||||
return fail(
|
||||
"suspensao_de_cobranca",
|
||||
"Esta suspensão é por falta de pagamento. Use Dar prazo ou Tornar isenta.",
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
* ── Leitura de `suspended_kind` ──────────────────────────────────────────────
|
||||
* Só significa algo com status='suspended'. O lgpd-redact-worker troca o status
|
||||
* para 'redacted' sem limpar o tipo, e por isso o banco NÃO tem CHECK de
|
||||
* coerência entre as duas colunas: quem lê o tipo confere antes que a org está
|
||||
* parada. Suspensão com tipo NULO (gravada por uma imagem anterior à 0501,
|
||||
* coerência entre as duas colunas: quem lê o tipo confere antes que o status é
|
||||
* 'suspended' — "parada" não basta, a redigida também é parada. Suspensão com tipo NULO (gravada por uma imagem anterior à 0501,
|
||||
* depois de um rollback) vale como `administrativa`, como nas funções de estado.
|
||||
*
|
||||
* ── Deliberadamente NÃO gatilhados (spec §4, decisões D-11 e D-12) ───────────
|
||||
|
||||
Reference in New Issue
Block a user