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ística | Detalhe |
|---|---|
| Módulo backend | backend/src/cashback/ |
| Schema | CashbackLedgerEntry |
| Unidade | Centavos de BRL (int) — sem ponto flutuante |
| Padrão de saldo | Corrente — balanceAfter desnormalizado por entrada |
| Permissão admin | Permission.SettingsManageGeneral |
| Rota admin | GET /t/:slug/admin/cashback/balances |
| Rota cliente | GET /t/:slug/cashback/balance/:customerId |
Schema CashbackLedgerEntry
| Campo | Tipo | Descrição |
|---|---|---|
tenant | ObjectId | |
customerId | ObjectId | |
type | enum | credit | debit | expire |
amount | number | Centavos (sempre positivo; sinal implícito no type) |
balanceAfter | number | Saldo corrente após a entrada (centavos) |
sourceOrderId | ObjectId? | Pedido que gerou o crédito |
expiresAt | Date? | Vencimento do crédito (apenas para credit) |
status | enum | active | used | expired |
Índices:
{ tenant, customerId, createdAt }— extrato paginado{ tenant, status, expiresAt }— cron de expiração
Operações
Credit
cashbackService.credit(tenantId, customerId, amountCents, sourceOrderId?, expiresAt?)Cria entrada type: 'credit' com balanceAfter = currentBalance + amount. Lança BadRequestException se amountCents < 1.
Debit (FIFO)
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)
// @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étodo | Rota | Descrição |
|---|---|---|
GET | /admin/cashback/balances | Lista todos os clientes com saldo positivo |
GET | /admin/cashback/balance/:customerId | Saldo de um cliente específico |
GET | /admin/cashback/ledger/:customerId | Extrato paginado (?page=1&limit=20) |
POST | /admin/cashback/debit | Débito manual (estorno/ajuste) |
Endpoints Cliente
| Método | Rota | Descrição |
|---|---|---|
GET | /cashback/balance/:customerId | Saldo do cliente autenticado |
POST | /cashback/redeem | Resgatar 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.