# Design — Empréstimo: parcela em dia útil

> Data: **2026-07-13**. Branch: `feat/loan-product-required-cosif-accounts`.
> Status: **aprovado no brainstorming**; pendente plano de implementação.
> Área: crédito (`SimulationDialog.vue` + `loans.ex`, reusando `Monetarie.UseCases.Calendar`).

## Objetivo

Opção na simulação de proposta, **ao lado da Periodicidade**: checkbox **"Parcela em dia útil"**.
- **Desmarcado** (default): comportamento atual — parcela `i` vence em `first_due + (i-1)*periodicidade*30 dias`.
- **Marcado**: cada data de vencimento (**incl. a 1ª**) que cair em **fim de semana ou feriado** é empurrada
  para o **PRÓXIMO dia útil** (`next_business_day`, fim de semana + feriados do calendário do sistema).

## Modelo de dados

Novo flag em `metadata`: **`business_day_adjust`** (bool). Enviado pelo front como a periodicidade;
default `false`/ausente = comportamento atual. Persiste na simulação → loan → usado no desembolso.

## Backend

### Calendário (existente, reusado)
`Monetarie.UseCases.Calendar` já expõe `next_business_day/2`, `business_day?/2`, `holiday?/2` com feriados
persistidos (tabela `holidays` + import nacional + CRUD admin). **⚠️ Gotcha:** `Calendar` colide com o
módulo **built-in do Elixir** → usar alias distinto (ex.: `alias Monetarie.UseCases.Calendar, as: BizCalendar`).

### `apply_periodicity` (loans.ex, no desembolso)
Hoje reescreve `due_date = first_due + (inst.number-1)*periodicity*30`. Passa a receber o flag
`business_day_adjust`; se on, aplica `BizCalendar.next_business_day(due_date)` em **cada** parcela (incl. a 1ª).
Helper `resolve_business_day_adjust(loan)` lê `metadata["business_day_adjust"]` (default false), espelhando
`resolve_periodicity`.

Periodicidade + juros **preservados** (só a data muda; o cálculo financeiro do `LoanEngine` é o mesmo).

## Frontend (preview fiel)

### Checkbox
"Parcela em dia útil" ao lado da Periodicidade (step preview). Ref `businessDayAdjust` (bool, default false).

### Feriados (para o mirror)
- Busca via **`GET /holidays?year=YYYY`** (HolidaysController) pros anos que o cronograma abrange.
- Cacheia num `Set` de datas ISO (`holidaysSet`) + anos já carregados. `ensureHolidays(years)` busca os faltantes.
- Trigger: quando `businessDayAdjust` on + first_due/term/periodicidade definidos → garante os anos do span do cronograma.

### Mirror em JS
`nextBusinessDay(date, holidaysSet)`: enquanto sáb/dom **ou** data ISO no Set → avança 1 dia. Espelha o backend.

### `schedule` (preview)
Se `businessDayAdjust`, cada data nominal (`first_due + (i-1)*per*30`) é ajustada por `nextBusinessDay`.
Todas, incl. a 1ª. Enquanto os feriados carregam, ajusta só por fim de semana; atualiza ao chegar (flicker aceitável).

### Submit / reset
Submit manda `metadata.business_day_adjust: businessDayAdjust`. Reset zera o flag.

## Edge cases
- **Reneg:** mantém a opção (dia útil é ortogonal ao net-funding).
- **Sem feriados carregados:** preview ajusta só fim de semana até o fetch chegar.
- **Feriado encadeado** (feriado seguido de fim de semana, ou pontes): `next_business_day` pula todos (loop até achar útil).

## Testes
- **Backend** (`loan_lifecycle_test.exs`): parcela nominal em sábado → segunda; em feriado → próximo útil;
  feriado + fim de semana encadeados; flag off = datas **inalteradas**; 1ª parcela ajustada; periodicidade preservada.
- **Front:** type-check; validação viva na tela (com um feriado conhecido dentro do range do cronograma).

## Fora de escopo (YAGNI)
- Direção "dia útil anterior" (escolhido: próximo).
- "Modified following" (não empurrar pra cruzar o mês).
- Editar simulação (`EditSimulationDialog`) — v1 no create, como o net-funding.

## Arquivos afetados (previsão)
| Arquivo | Mudança |
|---|---|
| `core/backend/lib/monetarie/use_cases/credit/loans.ex` | `apply_periodicity` + flag; `resolve_business_day_adjust`; alias `BizCalendar` |
| `core/apps/admin/src/views/credit/components/SimulationDialog.vue` | checkbox + fetch `/holidays` + `nextBusinessDay` JS + ajuste do `schedule` + submit |
| `core/backend/test/monetarie/credit/loan_lifecycle_test.exs` | testes de dia útil no desembolso |
