feat: add renewal invoice sweep

This commit is contained in:
sirily
2026-03-10 18:25:41 +03:00
parent 624c5809b6
commit eb5272d2cb
4 changed files with 410 additions and 11 deletions

View File

@@ -10,8 +10,11 @@ The current payment system covers:
- default subscription plan bootstrap
- user subscription creation at registration time
- invoice creation through a provider adapter
- automatic renewal-invoice creation `72 hours` before `currentPeriodEnd`
- one renewal-invoice creation attempt per paid cycle unless the user explicitly creates a new one manually
- manual admin activation after an operator verifies that the provider reported a final successful payment status
- automatic expiry of elapsed subscription periods during account and generation access checks
- automatic expiry of elapsed pending invoices
- quota-cycle reset on successful activation
The current payment system does not yet cover:
@@ -94,6 +97,17 @@ Current runtime note:
5. The returned provider invoice data is persisted as a new local `PaymentInvoice` in `pending`.
6. The API returns invoice details, including provider invoice id, amount, address, and expiry time.
## Automatic renewal invoice flow
1. The worker scans `active` manual-renewal subscriptions.
2. If `currentPeriodEnd` is within the next `72 hours`, the worker checks whether the current paid cycle already has an invoice.
3. If the current cycle has no invoice yet, the worker creates one renewal invoice through the payment-provider adapter.
4. The worker sends the invoice details to the user by email.
5. If any invoice already exists for the current cycle, the worker does not auto-create another one.
Current rule:
- after the first invoice exists for the current paid cycle, automatic re-creation stops for that cycle
- if that invoice later expires or is canceled, the next invoice is created only when the user explicitly goes to billing and creates one
## Payment status semantics
- `pending` does not count as paid.
- `pending` does not activate the subscription.
@@ -104,6 +118,7 @@ Current runtime note:
## Invoice listing flow
- `GET /api/billing/invoices` returns the user's invoices ordered by newest first.
- This is a read-only view over persisted `PaymentInvoice` rows.
- The worker also marks `pending` invoices `expired` when `expiresAt` has passed.
## Current activation flow
The implemented activation path is manual and admin-driven.