> ## Documentation Index
> Fetch the complete documentation index at: https://docs.lerian.studio/llms.txt
> Use this file to discover all available pages before exploring further.

# Como o Plugin SISBAJUD executa ordens

> Como o Plugin SISBAJUD recebe ordens judiciais, executa bloqueios, desbloqueios, transferências e requisições de informação no Midaz, e informa cada resultado.

O **Plugin SISBAJUD** executa ordens judiciais no ledger Midaz da instituição. As ordens vêm da Mensageria ou, no canal direto, do sistema da própria instituição. Esta página descreve como o plugin recebe uma ordem, o que cada operação escreve e como o plugin informa o resultado. [Operando o Plugin SISBAJUD](https://docs.lerian.studio/pt/interfaces/plugin-sisbajud/plugin-sisbajud-operations.md) descreve a configuração. [Como funciona o Lerian SISBAJUD](https://docs.lerian.studio/pt/rails/sisbajud/how-sisbajud-works.md) mostra como uma ordem passa da Mensageria para o Plugin SISBAJUD.

## Ciclo de vida da ordem

***

1. **Aviso.** O Streaming Hub envia um aviso de execução ao listener de webhook do plugin. O aviso traz o ID da ordem e a revisão da ordem, não a ordem.
2. **Verificação.** O plugin verifica a assinatura HMAC da entrega. Ele grava cada aviso assinado antes de responder.
3. **Busca.** O plugin obtém a ordem com `GET /v1/sisbajud/execution/orders/{orderId}` na API de execução da Mensageria.
4. **Verificação do dono.** Antes da sua primeira escrita, o plugin verifica que é dono da instituição da ordem.
5. **Execução.** No seu próximo ciclo, o plugin executa a operação no Midaz.
6. **Resultado.** O plugin envia o resultado com `POST /v1/sisbajud/execution/orders/{orderId}/execution-results`.

### Respostas do webhook

| Entrega | Resposta |
| - | - |
| O corpo é maior que 1 MiB. | `413`. O plugin não grava nada. |
| A assinatura HMAC está ausente ou é inválida. | `401`. O plugin não grava a entrega. |
| A assinatura é válida, mas o corpo não é um aviso utilizável nem um ping de verificação. | `200`. O plugin estaciona a entrega e dispara um alarme. |
| A Mensageria responde à busca com um status `4xx` diferente de `401`, `404`, `410` ou `429`. | `200`. O plugin estaciona a entrega e dispara um alarme. |
| A Mensageria ou um banco de dados falha. | `503`. O Streaming Hub tenta a entrega de novo. |
| O plugin aceita o aviso. | `200`. O plugin executa a ordem no seu próximo ciclo. |

O plugin aceita uma entrega com timestamp fora de `EXECUTOR_HUB_WEBHOOK_MAX_SKEW_SEC` e registra um aviso no log.

### Respostas da busca

| Resposta da Mensageria | O que o plugin faz |
| - | - |
| `200` | Executa a ordem. |
| `404` ou `410` | Trata a ordem como retirada. Ele não escreve nada no ledger. |
| `401`, `429`, um status `5xx` ou um erro de rede | Tenta a requisição de novo. |
| Qualquer outro status `4xx` | Estaciona a entrega e dispara um alarme. |
| `200`, com uma ordem de bloqueio cujo valor mínimo é maior que o seu valor | Não escreve nada no ledger e dispara um alarme. |

### Verificação do dono

O plugin escreve no ledger somente para as instituições das quais é dono. Quando cria uma instituição, ele registra o seu próprio subject M2M (`EXECUTOR_M2M_SUBJECT`) como dono.

* Se outra identidade é dona da instituição, o plugin não escreve nada e dispara um alarme.
* Se a instituição não tem configuração neste plugin, a ordem vai para uma decisão humana.

### Ciclo de execução

O plugin executa um ciclo a cada `EXECUTOR_TICK_EVERY`. O padrão é `30s`. Cada ciclo executa três etapas nesta ordem:

1. **Ingestão.** Executa os avisos aceitos.
2. **Verificação de órfãs.** Procura operações nas contas de bloqueio que o plugin não escreveu.
3. **Monitoramento.** Envia um heartbeat para cada escrita que não tem resultado conhecido.

Uma etapa com falha não interrompe as outras etapas. O plugin drena os resultados que esperam no outbox em um loop separado para cada canal, então um canal lento não segura o ciclo nem outro canal.

### Resultados

O plugin grava cada resultado em um outbox antes de enviá-lo. Cada envio traz o header `X-Idempotency`. Quando um envio falha com um erro transitório, o plugin envia o mesmo resultado de novo depois de uma espera, até `EXECUTOR_RESULT_MAX_ATTEMPTS` tentativas. O padrão é 12.

Depois da última tentativa, o plugin estaciona o resultado, registra uma decisão humana e dispara um alarme. Ele não envia de novo um resultado estacionado, e as versões posteriores da mesma ordem esperam atrás dele. Um administrador da plataforma rearma o resultado. [Operando o Plugin SISBAJUD](https://docs.lerian.studio/pt/interfaces/plugin-sisbajud/plugin-sisbajud-operations.md#orders-that-need-attention) descreve a rota.

| Campo | Valores |
| - | - |
| `executionState` | `ACCEPTED`, `EXECUTING`, `MONITORING`, `RESOLVED`, `INDETERMINATE`, `AWAITING_RECONCILIATION` |
| `effect` | `NONE`, `FULL`, `PARTIAL`, `INDETERMINATE` |

O `reasonCode` de cada operação está nas seções abaixo.

## Operações

***

O bloqueio e o desbloqueio escrevem no Midaz. A requisição de informação somente lê.

### Bloqueio (BLOQUEIO)

1. O plugin lê as contas ativas do sujeito. Um sujeito sem conta ativa recebe `NONE` com `NO_CLIENT`.
2. Ele aplica a restrição de agência e conta da ordem. [Restrição de agência e conta](#branch-account-restriction) dá as regras.
3. Ele bloqueia uma conta salário somente quando a ordem permite contas salário.
4. Ele bloqueia somente recursos próprios. Uma conta no cheque especial conta como 0.
5. Ele envia uma escrita ao Midaz. A escrita tem uma perna para cada conta de origem, e todas as pernas vão para a conta de bloqueio da ordem.

| Resultado | `effect` | `reasonCode` |
| - | - | - |
| O bloqueio cobre o valor ainda aberto na ordem. | `FULL` | `BLOCKED_TOTAL` |
| O bloqueio cobre menos que esse valor. | `PARTIAL` | `BLOCKED_PARTIAL` |
| Não há recursos disponíveis. | `NONE` | `NO_BALANCE` |

Uma ordem de bloqueio pode trazer um valor mínimo. Quando o total que o plugin pode bloquear fica abaixo desse mínimo, ele não escreve nada e passa a ordem para uma decisão humana.

#### Restrição de agência e conta

O plugin lê a agência e o número de cada conta nos instrumentos do CRM do sujeito. Com `crmMode` `embedded`, a agência é `bankingDetails.branch` e o número da conta é `bankingDetails.account`. Com `crmMode` `legacy`, o CRM não traz nenhum dos dois.

* Uma ordem que indica uma agência vai para uma decisão humana quando uma conta que pode ser a indicada tem agência desconhecida ou ambígua.
* Uma ordem que indica um número de conta bloqueia as contas cujo número coincide. Ela também bloqueia uma conta de número desconhecido ou ambíguo, até o valor da ordem, porque essa conta pode ser a que o tribunal indicou. As contas cujo número coincide vêm primeiro. Com `crmMode` `legacy`, nenhum número é conhecido, então toda conta que passa na regra de agência pode ser bloqueada.
* Uma ordem com número de conta e sem agência vai para uma decisão humana quando duas ou mais contas coincidem.
* Com um número de conta, o resultado é `NONE` quando todos os números de conta são conhecidos e nenhum coincide.

### Desbloqueio (DESBLOQUEIO)

O desbloqueio libera recursos de uma ordem de bloqueio pai, identificada por `parentOrderId`. O plugin usa a conta de origem registrada do bloqueio pai como destino da liberação. Se não consegue determinar um único destino com segurança, exige uma decisão humana em vez de adivinhar.

* Sem uma ordem pai, o resultado é `NONE` com `PARENT_UNRESOLVED`, e o plugin não escreve nada.
* Quando a ordem pai ainda não tem efeito conhecido, o plugin espera. No prazo da ordem menos `RESPONSE_DEADLINE_MARGIN`, a ordem vai para uma decisão humana. Se a ordem não tem prazo, ela vai para uma decisão humana na hora.
* O plugin lê a conta de bloqueio da ordem pai quando executa a ordem. Ele libera o menor de três valores: o valor que a ordem pede, o saldo restante da ordem pai e o saldo da conta de bloqueio.
* Quando o valor a liberar é 0, o resultado é `NOTHING_TO_RELEASE`.
* Quando uma conta do sujeito é uma conta salário, a ordem vai para uma decisão humana.

### Requisição de informação (REQUISICAO\_INFORMACAO)

O plugin lê os saldos do sujeito e não escreve nada no ledger. Se o sujeito é cliente, mas não é titular da conta especificada, o plugin exige uma decisão humana em vez de informar que o sujeito não é cliente.

* Um sujeito com pelo menos uma conta ativa recebe `FULL` com `INFO_FULFILLED`.
* Um sujeito sem conta ativa recebe `NONE` com `INFO_NON_CLIENT`.
* Uma ordem que indica uma agência vai para uma decisão humana.

Quando a ordem pede o saldo (`searchBalance`), o resultado traz dois totais: o total bloqueável e o total bloqueável das contas salário. Um sujeito sem conta ativa recebe 0.00 nos dois.

## Canal direto

***

No canal direto, o sistema da própria instituição envia ordens judiciais ao plugin, e a Mensageria não participa. O plugin guarda cada ordem, executa no Midaz e guarda os resultados. A instituição lê os resultados e responde ao tribunal ela mesma.

O plugin serve o canal direto apenas quando roda em modo executor, com um tenant, e com `PLUGIN_AUTH_ENABLED` ligado. Caso contrário, as cinco rotas diretas respondem `501`.

Um administrador da plataforma passa uma instituição para o canal direto com `PUT /v1/institutions/{institutionId}/channel`. A troca exige tudo isto:

* O plugin é o dono da instituição.
* O código da instituição guardado é a raiz de 8 caracteres do CNPJ do agrupamento responsável.
* A instituição não tem ordem aberta, e nenhum bloqueio da instituição ainda retém dinheiro.

A mesma rota devolve a instituição para a Mensageria. Uma instituição que não está no canal direto recebe `422` `SBJ-0025` em uma ordem direta.

| Rota | Finalidade |
| - | - |
| `POST /v1/institutions/{institutionId}/executor/orders` | Envia uma ordem ou uma revisão. Responde `202`. |
| `GET /v1/institutions/{institutionId}/executor/orders` | Busca as ordens por `externalReference`. |
| `GET /v1/institutions/{institutionId}/executor/orders/{orderId}` | Lê uma ordem. |
| `GET /v1/institutions/{institutionId}/executor/orders/{orderId}/results` | Lista as versões de resultado de uma ordem. |
| `GET /v1/institutions/{institutionId}/executor/results` | Lê os resultados da instituição como um feed por cursor. |

O feed de resultados entrega cada resultado pelo menos uma vez. Remova duplicatas por `orderId`, `orderRevision` e `executionVersion`. Envie um desbloqueio ou uma transferência apenas depois do `202` do seu bloqueio pai.

O canal direto aceita `BLOCK`, `UNBLOCK`, `TRANSFER`, `INFO` e `INTERRUPT`. Uma transferência move recursos da conta de bloqueio da ordem pai para a conta de depósito judicial da instituição. Uma interrupção para um bloqueio permanente e mantém o que o bloqueio já retém. `DIRECT_PERMANENT_BLOCK_ENABLED` decide se o canal aceita um novo bloqueio permanente. Com o padrão, ele recusa um com `422` `SBJ-0027`.

Um bloqueio permanente continua bloqueando novos créditos do sujeito, até o valor da ordem. O plugin lê esses créditos dos eventos do ledger Midaz. Ele dura um ano a partir do recebimento, ou até a data do tribunal quando a ordem informa uma, e nunca mais que um ano. Quando o prazo termina, o bloqueio deixa de aceitar novos créditos e mantém o que já retém. Uma interrupção, uma transferência ou um desbloqueio do restante, ou um cancelamento o encerra. Quando um bloco posterior de um bloqueio permanente continua falhando, o plugin estaciona a tentativa, levanta um alarme e deixa de tomar novos créditos desse bloqueio até que um administrador da plataforma resolva a tentativa. Uma ordem direta que falha em todas as tentativas, ou que chega ao seu corte enquanto o ledger falha, também é estacionada. A leitura dela mostra `parked` `true`.

Os papéis de máquina `order-submitter` e `result-reader` chamam essas rotas. [Operando o Plugin SISBAJUD](https://docs.lerian.studio/pt/interfaces/plugin-sisbajud/plugin-sisbajud-operations.md#roles) descreve os papéis.

### Apagar uma ordem do canal direto

Um administrador da plataforma apaga uma ordem concluída do canal direto com `POST /v1/admin/direct/orders/{orderId}/erase`, por um pedido do titular dos dados sob a LGPD ou no fim da retenção. `POST /v1/admin/direct/purge` lista as ordens que já podem ser apagadas e não muda nada. As duas operações exigem um token de usuário sem tenant e só respondem numa instalação de um tenant só.

Depois do apagamento, ninguém lê de novo o conteúdo enviado com a ordem: o corpo da ordem e o número do documento da pessoa ou empresa que a ordem atinge. O apagamento não tem volta. O seu `clientOrderId` e o seu `externalReference` viram tokens. Uma busca pelo `externalReference` original ainda encontra a ordem apagada, com o conteúdo oculto.

O apagamento não remove:

* o protocolo do tribunal e os números de sequência da ordem;
* o diário de lançamentos do plugin, com os valores, e as transações no Midaz;
* os resultados que já estão no feed de resultados, e o que o seu sistema já leu dele;
* o registro de auditoria do apagamento;
* os backups feitos antes do apagamento. Depois de restaurar um backup, apague a ordem de novo.

O plugin nunca apaga uma ordem sozinho. O apagamento recusa uma ordem ainda aberta, que ainda retém dinheiro ou que tem uma ordem filha aberta. Ele também recusa uma ordem de bloqueio com menos de um ano desde o primeiro lançamento no ledger, e um bloqueio permanente antes da data de fim. Quando uma ordem fica apta ao apagamento por mais tempo que `EXECUTOR_DIRECT_PURGE_ELIGIBLE_ALARM_AFTER` (padrão `168h`), o plugin registra um erro no log para um administrador revisar.

## Semântica do ledger

***

### Conta de bloqueio

O alias da conta de bloqueio tem o prefixo `@block_sisbajud_` e depois os 32 dígitos hexadecimais minúsculos do ID da ordem de bloqueio. Um desbloqueio encontra a conta pelo seu `parentOrderId`.

O tipo de conta de uma conta de bloqueio é `sisbajud_block`. Se o seu ledger valida tipos de conta, registre `sisbajud_block` como tipo de conta.

### Direções

* Um bloqueio diminui as contas do sujeito e aumenta a conta de bloqueio.
* Uma transferência diminui a conta de bloqueio da ordem pai e aumenta a conta de depósito judicial.
* Um desbloqueio diminui a conta de bloqueio. A escrita dele tem uma perna de origem: a conta de bloqueio. Ele libera os recursos para a conta de origem registrada ou exige uma decisão humana quando não é possível determinar um único destino seguro.

Um bloqueio move o valor do saldo disponível de cada conta do sujeito para o saldo disponível da conta de bloqueio.

### Idempotência

Cada escrita traz o header `X-Idempotency` e `X-TTL: 604800`, que são sete dias. O Midaz guarda a chave de idempotência de uma escrita por esse tempo. A chave é `orderId:orderRevision`, então uma reentrega da mesma revisão da ordem envia a mesma chave.

## Escritas incertas

***

Quando o Midaz responde a uma escrita sem prova do seu efeito, o resultado é `INDETERMINATE`. O plugin lê o ledger de novo antes de cada heartbeat. Ele envia um resultado de heartbeat à Mensageria a cada `EXECUTOR_HEARTBEAT_EVERY`, até que a Mensageria responda que a revisão da ordem foi substituída.

A ordem vai para uma decisão humana no primeiro de dois limites:

* `EXECUTOR_HUMAN_DECISION_AFTER_BEATS` heartbeats sem mudança. O padrão é 3.
* O prazo da ordem menos `RESPONSE_DEADLINE_MARGIN`.

O plugin então registra uma decisão humana. Na lista de decisões humanas, ela tem `humanDisposition` `HELD_MONEY_MOVED`. Os heartbeats continuam, com `executionState` e `effect` ambos `INDETERMINATE`.

### Ledger fora do ar no corte

O corte de uma ordem é o seu prazo menos `RESPONSE_DEADLINE_MARGIN`. Quando o Midaz falha para uma ordem da Mensageria no corte ou depois dele, e nenhum resultado judicial dessa revisão espera no outbox, o plugin para as suas tentativas. Ele registra uma decisão humana e não envia resultado. Verifique o ledger e responda ao tribunal você mesmo antes do prazo. Caso contrário, a Mensageria registra uma não resposta.

### Depois que uma pessoa responde

Considere uma revisão que foi passada a uma pessoa no seu corte, ou que uma pessoa resolveu como efeito reconhecido ou sem efeito comprovado. Quando a sua escrita chega ao Midaz depois, o plugin não envia resultado `FULL` nem `PARTIAL` para ela. Ele registra o efeito e dispara um alarme. O tribunal recebe apenas a resposta da pessoa, então concilie você mesmo um efeito tardio no ledger.

### Operações que o plugin não escreveu

A verificação de órfãs lê as operações de cada conta de bloqueio ao longo de `EXECUTOR_ORPHAN_RECONCILE_WINDOW`. O padrão é `48h`. O plugin informa uma operação como órfã quando a sua transação não tem `metadata.code`, ou tem um código que o plugin não registrou. Esta etapa somente detecta. Ela não muda nada no ledger.

## Rotas contábeis

***

As rotas contábeis são opcionais, por organização. O plugin as lê dos documentos de tenant `routing.organizations` e `routing.ledger_bindings` no Systemplane. Com `SYSTEMPLANE_ENABLED` desligado, o plugin escreve sem rotas.

Com `routing.organizations` em `schemaVersion` 2, cada organização tem as suas próprias rotas para cada fluxo e a lista de ledgers que lançam com elas. O plugin então não lê `routing.ledger_bindings`. Uma escrita em um ledger que não está na lista da sua organização sai sem rotas.

Quando uma escrita não pode sair por causa da sua configuração, o plugin a adia. O Midaz não aplicou nada, então a ordem espera, e uma entrega posterior envia a mesma escrita com a mesma chave de idempotência. Estas condições adiam uma escrita:

* O plugin não consegue resolver as rotas contábeis da escrita.
* O Midaz recusa as rotas contábeis da escrita: `422` com código `0113`, `0114`, `0116`, `0117`, `0118`, `0119`, `0152` ou `0157`, ou `404` com código `0105`.

Corrija a configuração antes do prazo da ordem. `GET /v1/admin/ledger-routing/preflight` verifica a configuração antes de você ligar as rotas.

## Chamadas ao Midaz

***

O plugin chama o ledger Midaz no `baseUrl` de cada instituição, com o token dessa instituição. Dê às credenciais da instituição acesso a estas operações:

| Finalidade | Operação do Midaz |
| - | - |
| Bloqueio | `POST /v1/organizations/{organizationId}/ledgers/{ledgerId}/transactions/block` |
| Desbloqueio | `POST /v1/organizations/{organizationId}/ledgers/{ledgerId}/transactions/unblock` |
| Transferência para a conta de depósito judicial | `POST /v1/organizations/{organizationId}/ledgers/{ledgerId}/transactions/json` |
| Criar uma conta de bloqueio | `POST /v1/organizations/{organizationId}/ledgers/{ledgerId}/accounts` |
| Encontrar uma conta pelo alias | `GET /v1/organizations/{organizationId}/ledgers/{ledgerId}/accounts?alias=` |
| Ler uma conta | `GET /v1/organizations/{organizationId}/ledgers/{ledgerId}/accounts/{accountId}` |
| Ler os saldos de um alias | `GET /v1/organizations/{organizationId}/ledgers/{ledgerId}/accounts/alias/{alias}/balances` |
| Ler as operações de uma conta de bloqueio | `GET /v1/organizations/{organizationId}/ledgers/{ledgerId}/accounts/{accountId}/operations` |
| Ler uma transação | `GET /v1/organizations/{organizationId}/ledgers/{ledgerId}/transactions/{transactionId}` |
| Encontrar as transações de uma escrita | `GET /v1/organizations/{organizationId}/ledgers/{ledgerId}/transactions?metadata.code=` |

O plugin encontra as contas de um sujeito pelo CRM do Midaz. Com `crmMode` `legacy`, ele chama `GET /v1/aliases?document=` em `crmBaseUrl`. Com `crmMode` `embedded`, ele chama `GET /v2/organizations/{organizationId}/instruments?document=` em `baseUrl`.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.