REF-501-03: CreditBalance & CreditPolicy
ADR: ADR-501 — Service DeliveryEscopo: Reserva/consumo FIFO, granularidade, expiração, carência, limites, extrato de movimentações, CreditBalance ativo mesmo zerado
0. Entity Fields (CreditBalance)
| Campo | Tipo | Descrição |
|---|---|---|
organization_id | int (FK) | Organization dona do saldo |
balance | decimal(10,2) | Saldo total disponível (nunca negativo) |
reserved | decimal(10,2) | Saldo reservado em ServiceRequests abertas |
currency | string | BRL | USD (segue billing_entity da Organization) |
updated_at | datetime | Último update do saldo |
Invariante: balance - reserved >= 0 — sempre.
Rules:
- 1 CreditBalance por Organization por currency
- Auto-criado quando domínio Service habilitado (mesmo com saldo zero — §7)
- Todas operações registradas em CreditBalanceTransaction (extrato — §6)
Operations:
| Operação | Descrição |
|---|---|
credit(amount, reason, reference_id) | Adiciona ao balance (compra de créditos, reembolso) |
reserve(amount) | Move de balance → reserved (abertura de SR) |
release(amount) | Move de reserved → balance (SR cancelada) |
confirm_debit(amount) | Debita de reserved (SR completada) |
1. Terminologia
| Contexto | Termo | Nota |
|---|---|---|
| Interno (código, banco, docs técnicos) | UST (Unidade de Serviço Técnico) | Nome permanente no sistema |
| Comercial (portal, cliente, negócio) | Crédito / Credit | Universal PT/EN, padrão indústria |
| Cálculo | 1 crédito = 10 unidades internas | Mínimo por serviço: 1 crédito |
2. Granularidade
| Regra | Detalhe |
|---|---|
| Crédito é inteiro | Nunca fracionário para o cliente |
| 1 crédito = 10 un. | Internamente, 10 unidades = 1 crédito |
| Mínimo por serviço | 1 crédito (nenhum serviço custa menos que 10 unidades) |
| Catálogo recalibrado | Serviços abaixo de 1 crédito sobem para 1 |
3. Reserva e Consumo (FIFO)
| Etapa | Comportamento |
|---|---|
| Abertura de SR | Créditos estimados reservados (soft-lock no saldo) |
| Conclusão de SR | Créditos reais consumidos (débito efetivo). Diferença ajustada. |
| Cancelamento SR | Reserva liberada integralmente |
| FIFO | Créditos mais antigos consumidos primeiro |
| Avulsos | Créditos comprados avulso com CreditPolicy separada |
Fluxo de Reserva
SR criada (ust_estimated = 4 créditos)
│
├── Saldo disponível ≥ 4?
│ ├── SIM → Reservar 4 (soft-lock, FIFO)
│ └── NÃO → Verificar CreditPolicy.block_on_limit_exceeded
│ ├── false → SR continua (billing avulso na conclusão)
│ └── true + threshold excedido → SR bloqueada
│
├── SR concluída (ust_actual = 5)
│ ├── Consumir 4 da reserva + 1 adicional (FIFO)
│ └── Se saldo insuficiente → billing avulso
│
└── SR cancelada
└── 4 créditos reservados liberados4. Expiração (CreditPolicy)
| Campo | Default | Descrição |
|---|---|---|
expiration_months | 12 | Meses até expiração de créditos do plano |
grace_before_days | 0 | Carência antes (antecipação com aprovação admin) |
grace_after_days | 30 | Carência após expiração |
avulso_expiration_months | 6 | Expiração de créditos comprados avulso |
Cron diário verifica créditos expirados. Hook: middag_credit_expired.
5. Limites de Consumo
| Campo | Default | Descrição |
|---|---|---|
block_on_limit_exceeded | false | Bloquear SRs quando saldo negativo excede threshold |
limit_threshold | 0 | Créditos negativos permitidos antes de bloqueio (0 = nenhum) |
block=false: SRs continuam com saldo zero/negativo. Excedente cobrado como avulso. block=true + threshold: SRs bloqueadas quando negativo excede threshold. Admin pode override.
6. Extrato de Movimentações
| Campo | Tipo | Descrição |
|---|---|---|
type | enum | credit / reserve / consume / release / expire |
amount | int | Quantidade (positivo = entrada, negativo = saída) |
sr_id | FK | ServiceRequest relacionada (se aplicável) |
balance_after | int | Saldo após movimentação |
created_at | datetime | Timestamp |
notes | string | Descrição (ex: "Reserva para SR-20260015") |
| Tipo | Quando | Amount |
|---|---|---|
credit | Créditos adicionados (plano ou avulso) | +N |
reserve | SR aberta, créditos reservados | -N (soft) |
consume | SR concluída, débito efetivo | -N |
release | SR cancelada, reserva devolvida | +N |
expire | Créditos expiraram (cron) | -N |
7. CreditBalance Ativo Mesmo Zerado
CreditBalance criado automaticamente quando Service habilitado — mesmo com saldo zero.
| Cenário | Comportamento |
|---|---|
| Service habilitado | CreditBalance criado (pode ter saldo 0) |
| Saldo = 0 | SRs continuam (billing avulso), extrato registra |
| Service desabilitado | CreditBalance preservado (dados não apagados) |
| Portal | Se saldo = 0: "Créditos não incluídos no plano" |
Justificativa: mensurar custo operacional real por Organization.
8. Alerta de Saldo Baixo
Saldo disponível < credit_low_threshold_pct (default: 20%) → hook middag_credit_balance_low. NotificationPolicy determina canais.