feat: automated billing cycles, dunning retry, promo integration, reports UI [#1198 #1199 #1200 #1201]#1262
Merged
yusuftomilola merged 2 commits intoJun 28, 2026
Conversation
…ation, reports frontend (DistinctCodes#1198-DistinctCodes#1201) - BE-25: BillingCycle entity + BillingService with daily cron to generate monthly cycles for MONTHLY bookings; GET /billing/cycles (admin) and /billing/my-cycles (member) - BE-26: DunningService with daily 06:00 cron retrying failed billing cycles using staggered delays (1d → 3d → 7d); auto-cancels after 3 exhausted retries - BE-27: POST /promo-codes/apply endpoint records promo usage against a booking and updates booking.totalAmount, appliedPromoCodeId, promoDiscountApplied atomically - FE-23: /admin/reports page with 4 tabs (Bookings, Revenue, Members, Occupancy), from/to date range filters, CSV export button, and summary stat cards for revenue/members views
|
@Tinna23 is attempting to deploy a commit to the naijabuz's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
@Tinna23 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
yusuftomilola
approved these changes
Jun 28, 2026
7 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #1194
Closes #1195
Closes #1196
Closes #1197
BE-25 — Automated Billing Cycles for Monthly Bookings
Introduces a
BillingCycleentity andBillingServicewith a nightly cron job:BillingCycleentity (billing_cyclestable):bookingId,userId,periodStart,periodEnd,amountKobostatus:pending | invoiced | paid | failed | cancelledinvoiceId(linked when paid),retryCount,nextRetryAt,failureReasonCron job (
@Cron(EVERY_DAY_AT_MIDNIGHT)): scans allCONFIRMEDbookings withplanType = MONTHLYand creates oneBillingCycleper day if one doesn't already exist for that period. Idempotent — skips already-created cycles.Endpoints:
GET/billing/cyclesGET/billing/my-cyclesBE-26 — Failed Payment Dunning & Retry Logic
DunningServiceruns daily at 06:00 (@Cron('0 6 * * *')). It:FAILEDbilling cycles wherenextRetryAt <= nowretryCountand schedules the next retry based on a staggered delay schedule: +24 h → +72 h → +168 hThe design is a clean hook point — the actual payment charge call would be inserted into
processFailedPayments()where noted, without changing the retry scheduling logic.BE-27 — Promo Code → Booking Integration
The
PromoCodesModuleandPromoCodeentity already existed. This PR wires promo codes directly into confirmed bookings:New endpoint:
POST /promo-codes/applyBody:
{ code, bookingId, bookingAmount }Flow:
POST /promo-codes/validate— checks expiry, usage limits, workspace restrictions, per-user usage)Bookingrow: setsappliedPromoCodeId,promoDiscountApplied, and the reducedtotalAmountPromoCodeUsageentry and increments the promo code'susedCount— all in a single transactionNew DTO:
ApplyPromoCodeDto(code,bookingId,bookingAmount)FE-23 — Advanced Reports Frontend (
/admin/reports)Full-featured reports dashboard with four tabs:
Features:
From/Todate pickers — passed as ISO strings to the backendGET /reports/:tab?format=csvand downloads the file via a temporary object URL (no server-side redirect needed)Files Changed
Backend
backend/src/billing/entities/billing-cycle.entity.ts(new)backend/src/billing/billing.service.ts(new)backend/src/billing/billing.controller.ts(new)backend/src/billing/billing.module.ts(new)backend/src/dunning/dunning.service.ts(new)backend/src/dunning/dunning.module.ts(new)backend/src/promo-codes/dto/apply-promo-code.dto.ts(new)backend/src/promo-codes/promo-codes.service.ts(applyToBooking method)backend/src/promo-codes/promo-codes.controller.ts(POST /apply endpoint)backend/src/promo-codes/promo-codes.module.ts(Booking entity added to TypeORM feature)backend/src/app.module.ts(BillingModule, DunningModule registered)Frontend
frontend/app/admin/reports/page.tsx(new)frontend/components/dashboard/DashboardSidebar.tsx(Reports link in admin nav)Test Plan
GET /billing/cyclesreturns all;/billing/my-cyclesscoped to userPOST /promo-codes/applywith a valid code updates booking total and records usage/admin/reportsloads all 4 tabs with correct data