Manual student enrollment: tier bypass + payment bookkeeping - #93
Manual student enrollment: tier bypass + payment bookkeeping#93projectamazonph wants to merge 4 commits into
Conversation
The manual enrollment flow at /admin/enroll (grant a pricing tier without a PayMongo payment) existed but was only reachable via direct URL or from a student's detail page, not from the main admin nav.
/admin/enroll now lets the admin note how a student paid outside the platform (method, amount, free-text reference) when granting a tier. grantManualEnrollment() creates a single COMPLETED Payment row for the grant (not tied to one course enrollment, since a tier can bundle several) so it shows up under the student's Payments in the admin panel. Recording payment is optional — comp/free grants still work exactly as before with no Payment row. Also fixed the Payments badge on the student detail page, which checked payment.status against 'PAID', a value the app never uses (the real enum value is 'COMPLETED'), so completed payments always rendered as the default gray badge.
|
Warning Review limit reached
Next review available in: 49 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📝 WalkthroughWalkthroughManual enrollment now optionally records completed payments, validates and audits payment details, exposes payment fields in the admin form, and displays payment status and metadata in admin user records. ChangesManual enrollment payment recording
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
actor Admin
participant EnrollForm
participant manualEnrollAction
participant grantManualEnrollment
participant PaymentStore
Admin->>EnrollForm: Enter enrollment and optional payment
EnrollForm->>manualEnrollAction: Submit validated payment payload
manualEnrollAction->>grantManualEnrollment: Forward enrollment and payment
grantManualEnrollment->>PaymentStore: Create completed payment row
grantManualEnrollment-->>manualEnrollAction: Return paymentRecorded
manualEnrollAction-->>EnrollForm: Return enrollment result
EnrollForm-->>Admin: Show payment recorded status
Possibly related PRs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/lib/enrollment.ts`:
- Around line 153-177: Make manual tier-grant payment and audit recording
retry-safe and atomic: in src/lib/enrollment.ts lines 153-177, add durable
idempotency for the grant, avoid creating payments when toCreate is empty, and
derive paymentRecorded from the actual insert result; in
src/app/actions/admin-enroll.ts lines 66-78, persist the audit entry within the
same transaction or via a durable outbox so committed mutations cannot return
unaudited errors. Add regression tests covering retries and audit-write
failures, asserting exactly one payment and one audit record.
- Around line 154-155: Update the comment describing the tier payment behavior
near the enrollment grant logic to replace the em dash with an allowed
punctuation mark, preserving the existing meaning and wording.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 9dfb8ed7-60a2-4461-818d-bf0f7097d545
📒 Files selected for processing (8)
src/app/actions/admin-enroll.tssrc/app/admin/enroll/EnrollForm.tsxsrc/app/admin/enroll/enroll.module.csssrc/app/admin/enroll/page.tsxsrc/app/admin/users/[id]/page.tsxsrc/components/ui/Icon.tsxsrc/components/ui/NavSidebar.tsxsrc/lib/enrollment.ts
Addresses a CodeRabbit review finding on PR #93: the AuditLog write happened as a separate db call after the enrollment/payment transaction committed. If that write failed, the action returned an error even though the Payment row already existed — and since nothing gated payment creation on idempotency, retrying the same submission would create a duplicate COMPLETED payment. grantManualEnrollment() now accepts an `audit` context and writes the AuditLog row with the same transaction client as the enrollment and payment writes, so the whole grant commits or rolls back together. Also fixed an em dash CodeRabbit flagged in a comment (repo style guidelines prohibit them). Not done: a durable idempotency key / outbox pattern for the payment write itself, which CodeRabbit's suggestion also called for. This is a low-traffic, solo-admin internal tool where an accidental duplicate payment is easy to spot and soft-delete in the admin UI; the atomicity fix above removes the concrete failure mode described (committed payment reported as failed, prompting a retry). Skipping the added infra as disproportionate to this feature's scope.
CI's Quality Gates job failed on 3eca663: global branch coverage dropped to 68.39%, below the 70% threshold, because the new if (payment) / if (audit) branches in grantManualEnrollment() had no test coverage. Adds three cases to enrollment.test.ts: no payment/audit provided, a payment + audit recorded together (asserting the Payment and AuditLog write shapes, including the JSON metadata), and audit provided without a payment (null metadata). enrollment.ts branch coverage goes from 57.14% to 92.85%, bringing the global figure to 71.55%.
Summary
/admin/enroll— grant a pricing tier without a PayMongo payment, for students paying outside the platform) in the admin sidebar nav, where it wasn't previously linked.COMPLETEDPaymentrow for the grant (not tied to a single course enrollment, since a tier can bundle several courses), which now shows up under the student's Payments on/admin/users/[id]. Recording payment is optional — comp/free grants still work with noPaymentrow created.payment.status === 'PAID', a value the app never sets (the real enum value is'COMPLETED'), so completed payments always rendered as the default gray badge instead of green/success.Test plan
pnpm typecheck— confirmed the touched files introduce no new errors (63 pre-existing errors both before and after this change, all from the ungenerated Prisma client in the sandbox with noDATABASE_URL)eslinton all changed files — clean/admin/enroll→ check "record a payment" → submit → confirmPaymentrow appears on/admin/users/[id]with correct method/amount/reference and a green "COMPLETED" badgeGenerated by Claude Code
Summary by CodeRabbit