# Contabilização COSIF dos custos adicionais no desembolso

- **Data:** 2026-07-09
- **Autor:** Bruno + Claude
- **Status:** Aprovado (design) — implementando
- **Arquivo:** `core/backend/lib/monetarie/use_cases/credit/loans.ex` (motor de desembolso)

## 1. Problema

Os custos adicionais do produto (`metadata.additional_costs`) têm par Débito/Crédito
COSIF configurado (`cosif_debit`/`cosif_credit`), mas **nenhuma rotina contabiliza** com
ele. Hoje, no `disburse_loan`, um custo com `launches_in_account` gera só um `AccountEntry`
(débito no extrato da CC do cliente); o `create_disbursement_journal_entry` lança **só**
principal + IOF no COSIF. O par D/C do custo é ignorado.

## 2. Decisões (confirmadas com o Bruno)

1. **Todos os custos** com **valor > 0** geram JE COSIF no desembolso — **sem** gate de
   `launches_in_account`.
2. **Partida:** **D = `cosif_debit`** / **C = `cosif_credit`** (o par configurado), com o
   token `"__conta_corrente__"` resolvido para a **conta contábil da CC do cliente**
   (`mon_code`).
3. **Fail-soft** (igual principal/IOF): conta COSIF não encontrada → loga aviso e **segue**
   (não reverte o desembolso; o dinheiro já commitou na transação).

## 3. Escopo técnico

- **Backend-only**, `loans.ex`. Exige **rebuild do core-api** + rodar nada de migration.
- Reusa `AccountingBridge.fetch_cosif_ids/2`, o helper `create_loan_cosif_je` (fail-soft,
  chama `Cosif.create_journal_entry`) e a resolução de `mon_code` (CC do cooperado) que já
  existem.
- **Sem dupla contagem:** o bridge genérico `AccountEntry`→COSIF **não roda** no
  `disburse_loan` (confirmado: `create_journal_entry_fail_soft` não é chamado lá; o
  `insert_all` não devolve structs). O JE do custo é a **única** entrada COSIF do custo.

## 4. Onde (fluxo)

Dentro de `create_disbursement_journal_entry` (chamado **após** o `Multi` commitar,
fail-soft fora da transação), **depois** dos JEs de principal/IOF, iterar os custos do
produto e lançar um JE por custo. A função já tem `mon_code`, o produto, a data, `loan_id`
e `contract_number`.

## 5. Por custo (`product.metadata.additional_costs`, valor > 0)

- **Valor** = `bps` ? `div(disbursed_amount × value, 10_000)` : `fixed_cents` (mesmo cálculo
  do extrato hoje). Em **centavos** (o JE COSIF usa centavos, como principal/IOF — NÃO ×100).
- **Débito** = `resolve_cost_cosif_code(cosif_debit, mon_code)`; **Crédito** =
  `resolve_cost_cosif_code(cosif_credit, mon_code)`, onde:
  - token `"__conta_corrente__"` → `mon_code`;
  - código → `String.replace(code, "-", ".")`;
  - vazio/nil → `nil` (loga e pula o custo — não deveria ocorrer: par é obrigatório na tela).
- `AccountingBridge.fetch_cosif_ids(débito, crédito)` → `{:ok, debit_id, credit_id}`.
- `create_loan_cosif_je(debit_id, credit_id, valor_cents, date, loan_id, contract_number,
  "loan_additional_cost", "<nome> - Contrato <n>", reference_id)` com **`reference_id`
  único por custo** = `"#{loan_id}:#{cost_id}"` (o `id` do custo). Para isso, `create_loan_cosif_je`
  ganha o parâmetro `reference_id` (os 2 callers atuais — principal/IOF — passam `loan_id`,
  comportamento inalterado).

## 6. Sem dupla contagem (razão × sub-razão)

Para custo com `launches` marcado (D=CC): o `AccountEntry` já debita a CC do cliente
(**sub-razão**); o JE COSIF (D=CC / C=receita) é a camada **razão** do mesmo débito — igual
o principal, que credita a CC no extrato e no COSIF. Uma entrada em cada camada, sem duplicar.

## 7. Caveat (escolhido pelo dono)

Custo **sem** `launches` gera JE COSIF mas **não** gera `AccountEntry` (extrato). Se um custo
sem `launches` tiver `cosif_debit` = Conta Corrente, o razão debita a CC sem o extrato — uma
divergência que a config do usuário cria. Intencional (o dono escolheu "todos os custos").

## 8. Fora de escopo

- **Extrato (`AccountEntry`):** inalterado (débito na CC segue só pros `launches`).
- **admin_fee / prestamista (seguro):** não têm par D/C configurável; fora.
- **Migration/schema/tela:** nada.

## 9. Arquivo tocado

| Arquivo | Mudança |
|---|---|
| `core/backend/lib/monetarie/use_cases/credit/loans.ex` | JE COSIF por custo no desembolso: `create_additional_costs_cosif_jes` + `resolve_cost_cosif_code`; `create_loan_cosif_je` ganha `reference_id` (2 callers passam `loan_id`) |

## 10. Validação (runtime, monetarie-local, ao centavo)

- Rebuild do core-api; configurar produto com 1–2 custos (um `launches`=CC, um COSIF puro);
  desembolsar um contrato.
- Conferir: cada custo gerou **um** JE COSIF em `cosif_journal_entries` com D/C corretos e
  valor certo; partida **balanceada** (débito = crédito); `reference_id` único por custo.
- Conferir o extrato: débito na CC só pros `launches` (inalterado).
