Skip to content

Cashback — Ledger de Créditos

O módulo cashback (backend/src/cashback/) mantém um ledger de dupla entrada de créditos em centavos por cliente, com expiração automática por cron e endpoints de consulta de saldo e extrato.

Visão Geral

CaracterísticaDetalhe
Módulo backendbackend/src/cashback/
SchemaCashbackLedgerEntry
UnidadeCentavos de BRL (int) — sem ponto flutuante
Padrão de saldoCorrente — balanceAfter desnormalizado por entrada
Permissão adminPermission.SettingsManageGeneral
Rota adminGET /t/:slug/admin/cashback/balances
Rota clienteGET /t/:slug/cashback/balance/:customerId

Schema CashbackLedgerEntry

CampoTipoDescrição
tenantObjectId
customerIdObjectId
typeenumcredit | debit | expire
amountnumberCentavos (sempre positivo; sinal implícito no type)
balanceAfternumberSaldo corrente após a entrada (centavos)
sourceOrderIdObjectId?Pedido que gerou o crédito
expiresAtDate?Vencimento do crédito (apenas para credit)
statusenumactive | used | expired

Índices:

  • { tenant, customerId, createdAt } — extrato paginado
  • { tenant, status, expiresAt } — cron de expiração

Operações

Credit

typescript
cashbackService.credit(tenantId, customerId, amountCents, sourceOrderId?, expiresAt?)

Cria entrada type: 'credit' com balanceAfter = currentBalance + amount. Lança BadRequestException se amountCents < 1.

Debit (FIFO)

typescript
cashbackService.debit(tenantId, customerId, amountCents, sourceOrderId?)

Consome créditos mais antigos primeiro (createdAt ASC, status: active, não expirados). Lança BadRequestException se o saldo for insuficiente. Gera uma ou mais entradas type: 'debit' + atualiza status: 'used' nos créditos consumidos.

Expiração (Cron)

typescript
// @Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT)
cashbackService.expireExpiredCredits()

Busca todas as entradas { status: 'active', expiresAt: { $lt: now } } e as marca como expired, criando entradas type: 'expire' para auditoria.

Endpoints Admin

MétodoRotaDescrição
GET/admin/cashback/balancesLista todos os clientes com saldo positivo
GET/admin/cashback/balance/:customerIdSaldo de um cliente específico
GET/admin/cashback/ledger/:customerIdExtrato paginado (?page=1&limit=20)
POST/admin/cashback/debitDébito manual (estorno/ajuste)

Endpoints Cliente

MétodoRotaDescrição
GET/cashback/balance/:customerIdSaldo do cliente autenticado
POST/cashback/redeemResgatar cashback no checkout

Integração com Pedidos

CashbackService.credit() é chamado pelo OrdersService após o pedido ser marcado como delivered / paid. A percentagem de cashback (ex: 5% do valor do pedido) é configurável nas configurações do tenant.

Relacionados

Lançado sob a licença MIT.