feat(platform): Billing > Fechamentos e Relatórios
GET /billing/periods e /billing/statements só serviam o próprio tenant do JWT — sem uso pra um platform admin escolhendo um tenant arbitrário. Adicionado GET .../by-tenant/:tenantId nos dois (mesmo padrão já usado em Subscriptions), e GET /billing/statements/:id ganhou um ?tenantId= opcional só aceito de quem tem role de plataforma. Frontend: /platform/billing/fechamentos (fecha/reabre período por tenant, seletor via querystring pra não duplicar rota) e /relatorios (statements por tenant, detalhe com itens por categoria). Bug real achado testando o fluxo: fechar um período de 01/08 a 31/08 mostrava "31 de jul." a "30 de ago." — meia-noite UTC de uma data-only vira o dia anterior no timezone local do servidor. Corrigido com formatDateUTC novo, usado só em fronteiras de calendário (não em timestamps de verdade, que continuam com formatDate local). Testado ponta a ponta contra a API real: período fechado, statement gerado (R$ 0,00 honesto — Acme sem assinatura/price book ainda), detalhe correto. Smoke test nas 19 telas do tenant + 8 telas platform, todas 200. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01BFaBaBSQGhyXGEgtTYZGV8
This commit is contained in:
47
TODO.md
47
TODO.md
@@ -1287,6 +1287,53 @@ Saúde (agente.md secao 148, 150-151, 168, 187)
|
||||
platform-wide (ver GLOBAL, agregar uso/custo entre tenants) não foi
|
||||
construída ainda
|
||||
|
||||
## PHASE 35 — Platform: Billing > Fechamentos e Relatórios (agente.md
|
||||
secao 134-139, 168)
|
||||
- [x] **Lacuna de backend fechada primeiro**: `GET /billing/periods` e
|
||||
`GET /billing/statements` só serviam o próprio tenant do JWT — sem
|
||||
uso pra um platform admin escolhendo um tenant arbitrário (a mesma
|
||||
exceção já resolvida em Subscriptions na PHASE 22, só não tinha
|
||||
sido replicada aqui ainda). Adicionado `GET /billing/periods/by-
|
||||
tenant/:tenantId` e `GET /billing/statements/by-tenant/:tenantId`
|
||||
(mesmo padrão), e `GET /billing/statements/:id` ganhou um
|
||||
`?tenantId=` opcional só aceito de quem tem role de plataforma
|
||||
(nunca confiado sem essa checagem, secao 31).
|
||||
- [x] Frontend: `/platform/billing/fechamentos` (seletor de tenant via
|
||||
`?tenantId=` na própria URL — sem isso, 4 itens de menu
|
||||
apontariam pro mesmo lugar; um seletor dentro da página resolve sem
|
||||
duplicar rota) — lista períodos, fecha um novo (intervalo de
|
||||
datas), reabre um fechado com motivo obrigatório.
|
||||
`/platform/billing/relatorios` — lista statements por tenant,
|
||||
detalhe com itens por categoria + subtotal/ajustes/total. Nunca
|
||||
chamado de "nota fiscal" na UI (PRODUCT.md).
|
||||
- [x] **Bug real, achado testando o fluxo completo**: fechar um período
|
||||
de 01/08 a 31/08 mostrava "31 de jul." a "30 de ago." na tela —
|
||||
meia-noite UTC de uma data-only vira o dia anterior quando
|
||||
formatada no timezone local do servidor (America/Sao_Paulo,
|
||||
UTC-3). `formatDate` (local) está certo pra timestamps de verdade
|
||||
(criado em, gerado em), mas errado pra fronteiras de calendário.
|
||||
Corrigido com `formatDateUTC` novo em `lib/format.ts`, usado só
|
||||
onde o valor é uma fronteira de período, não um instante.
|
||||
- Achado incidental durante a investigação (não um bug de produto):
|
||||
um 404 na tela de detalhe do statement era eu mesmo esquecendo de
|
||||
reiniciar `apps/api` depois de editar o `get()` do controller —
|
||||
confirmado isolando com um cliente Prisma direto (achou a linha
|
||||
sem problema) antes de suspeitar da camada HTTP.
|
||||
- [x] Testado ponta a ponta contra a API real: fechado um período de
|
||||
agosto/2026 pro tenant Acme (sem assinatura/price book atribuído
|
||||
ainda, então R$ 0,00 — honesto, não um erro), aparece em
|
||||
Fechamentos com as datas certas, gera um statement visível em
|
||||
Relatórios, detalhe mostra 0 itens/subtotal/total corretos. Smoke
|
||||
test de regressão nas 19 telas do tenant + 8 telas platform, todas
|
||||
200.
|
||||
- [ ] "Billing > Consumo" continua "em breve" — distinção de escopo com
|
||||
"Relatórios" nunca ficou 100% clara na especificação (secao 138 vs
|
||||
135); vai depender de decidir se é uma view de uso corrente
|
||||
(período aberto) ou se sobrepõe com o dashboard de plataforma
|
||||
- [ ] Sem exclusão de statement nem edição manual de item — statements
|
||||
são gerados, nunca editados à mão (consistente com "fechamento
|
||||
imutável", secao 137)
|
||||
|
||||
---
|
||||
|
||||
## Riscos conhecidos
|
||||
|
||||
Reference in New Issue
Block a user