Subscription — End-user view
Two main roles: admin/staff (setup & management) and customer (enroll & book). Below is each role's journey.
A. Admin/Staff sets up a package
1. Create Subscription
Page
Admin Portal → Setup → Subscription(/product-service/subscription).
- Table is split into Current (not archived) and Archived.
- Create a new package: choose Site (one site), enter Subscription Name, choose type (Billing Only or default BookingAndBilling).
- Configure: price (Price), image, Booking Cut-Off (number of days), rich text (Booking Info, Instructions, Discount Info, Payment Instructions, Important Notice), and period-selection permissions: Booking Start/End Selection (
Staff OnlyorStaff & Customer).
2. Link with Term
- Open linked-term confirmation popup: choose each SubscriptionProduct (no "Select All").
- Package with no product → popup says "please add sessions in Program first".
- The link-term API auto-validates product compatibility with the term; missing items → show a list of missing products.
3. Manage through Subscription Manager
Filter by Site/Subscription/Term/Account/Attendee/Status; changing a filter does not auto-reload — click Apply to load (initial page load runs automatically; a successful mutation also refreshes).
- Each enrollment row expands to show the applied add-ons and discounts.
- Actions: Manage Add-ons, Manage Discounts (only for the enrollment's booked periods).
- View (row action) → Booked Periods drawer, read-only: lists the enrollment's booked Enrollment Schedules + a View Calendar link (active periods only, not cancelled). The drawer has no edit/cancel/payment actions.
- The enrollment id shows as
SBK-{id}(instead ofSUB-); the date column is named Booking Range. - Terminate Enrollment: the end date can only be picked from the booked period's
BookingEnd; the backend rejects dates that do not match. - Confirm/Terminate/Cancel all have a confirmation with Mute Notifications (default off) — skips emails that would otherwise be sent; the lifecycle still runs.
- Notes show two read-only blocks: Admin Notes (admin-only) and Notes (customer-facing).
Real-world example: Admin terminates An's package. → Avoid terminating at the wrong boundary. → Open View → Booked Periods drawer (SBK-101047); the dropdown only lists the BookingEnd of booked periods; picking another date → the backend rejects it.
4. Billing Details: invoice actions
The Subscription Billing Details page displays by invoice (one row/invoice), and does not show internal logs.
Three main actions, all operating on the invoice:
| Action | Result |
|---|---|
| Schedule | Creates InvoiceScheduler for each invoice; ScheduledOn = Invoice.Date (UTC). |
| Approve | Changes invoice to Approved + creates a scheduler immediately (ScheduledOn = UtcNow). |
| Skip | Cancels the running scheduler + resets invoice to Initialised (0). |
- Drill-down: only entered from Billing Manager via the View button (with site/subscription/ term context); opening directly without enough context → redirects to a safe page.
- On open: if the uninvoiced count > 0 → a non-closable Generate Billing Required modal forces Generate Billing before any action.
Real-world example: Admin clicks View on a schedule that is missing invoices. → Generate enough invoices before scheduling/approving. → A non-closable "Generate Billing Required" modal appears; click Generate Billing, then continue.
5. Subscription Billing Manager
The finance sidebar Subscription Billing opens the Subscription Billing Manager page; the Billing Details page only opens from a row's View button.
- Filter Site + Subscription (required, single-select) + Term (optional; empty = all terms of the subscription); click Apply to load the table.
- Subscription filter options come from
/Subscription/WithTerms(not/Subscription/List; does not readPeriods). - Each row = one
SubscriptionTermBillingSchedule(an archived term withStatusId=600still shows): Term, Period (PeriodStart→PeriodEnd), Invoice Date, Due Date, Stats, Action. - Stats
generated/expected(generated / expected per active-approved enrollment); missing → info icon "There are x more invoices to be generated, please click "View" button to proceed." - View → redirects to Billing Details with site/subscription/term context.
- Non-SuperAdmin (
BusinessUnit.TypeId ≠ 99): manager is read-only — approve/skip/generate only on the detail page; the table has no column filters. - SuperAdmin (
TypeId = 99): rows get a Calculate link → summary drawer (GET /api/subscription-billing/ScheduleSummary/{id}) + a Generate Subscription Booking button (POST /api/ConsumerEnrollment/BillingEnrollment/{scheduleId}); closing the drawer → refreshes the grid.
Real-world example: Finance reviews invoice generation progress for the term. → A per-schedule overview instead of digging through each invoice. → Pick Site + Subscription, leave Term empty, click Apply; a row with generated < expected → info icon → click View to handle it in the detail page.
B. Customer enrolls & books
1. Browse & select package (Course List)
- Card shows: title, price (when present), weekday schedule (Mon–Sun), description, image, site info (map popup).
2. Subscription Booking (Step 1 → Step 2)
Step 1 — choose package & range (public, no login needed to view):
- Shows: configured title, site (map icon), price/frequency, weekday indicators, requirements, image/share; no Basic Info box.
- Program Details: each row = Program + session, time range, weekly pattern; the header has View Calendar (derived from Term Planner × TermProducts of the term, closure days removed).
- Range selection follows the package's Booking Start/End Selection permission:
Staff Only→ customer does not choose: every schedule shows as selected, checkboxes disabled.Staff & Customer→ customer chooses; the range is contiguous (start→end / start→end / pick start then pick end in a modal); showsSelected {x}/{total}; > 12 rows → View More Schedules.
- Cut-off: a schedule cannot be selected when
BookingStart< now +CutOffMinute(anchored toBookingStart, notPeriodStart). - Bottom toolbar:
Total Fee per Attendee+ Next (enabled when the range is valid). Anonymous users clicking Next → login popup (range kept) → T&C popup (if configured). - Preview mode
?isPreview=true: shows everything but is read-only; no submit/book.
Admin Mode Step 1 — Booking Rule Options (staff only, shown before Program Details):
- Booking Cut-off panel (when
CutOffMinute > 0) + a toggle per requirement (Age/School Year/ Level/Height/Weight/Swimming — when the Product has bounds and<Reference>_Enabled = true). - Toggles are transient (not persisted), default ON; OFF → that dimension is ignored during selection/submit.
- Customers don't see the panel and cannot bypass it (the client bypass flag is ignored).
Requirements from Product: the attendee must meet the requirements of the Products in the selected term (age/school year/level/height/weight/swimming); failing → schedule selection is blocked (Step 1) + submit is rejected (Step 2, backend revalidates). Details in Concepts.
Step 2 — Booking Details (login required):
- Booking Summary: site, subscription name, program/session + weekly pattern; View Calendar button.
- Booking Range: read-only (must go back to Step 1); each row shows Booking/Add-on/Total, the
Total Countsum,View Calendarper schedule. - Account Holder: customer → preloads their account; admin → must Select an Account or pick the attendee first (no preload from route context).
- Attendees: follows the Course Booking pattern; an attendee who already has an enrollment for this package → View Existing Booking link → read-only Booked Periods drawer.
- Additional Info: comments (customer); Admin Booking Notes (admin only).
- Add-ons: groups
Normal Add-ons/Bus Service, unit price by frequency (/ month,/ week,/ term); selecting updates the toolbar + the Booking Range Add-on amount. - Enrichment: weekday grid (checkbox ALL + each weekday per weekly pattern) — hidden behind a feature flag; flag off → not rendered, submit uses empty selections.
- Bottom toolbar:
Total Fee per Attendee(booking + add-on/enrichment); admin has Submit or Submit & Confirm (customer only gets Submit); both have Mute Notifications (default off).
3. Booking is checked for schedule clash
On submit, the system checks for schedule clash against the attendee's existing enrollments/bookings. On a clash → the whole request fails (no partial state).
4. Portal: My Subscriptions
Customers view their subscriptions in Customer Portal → My Subscriptions.
5. Booking lifecycle notifications
| Event | Template sent |
|---|---|
| Submitted (still pending) | New Subscription Booking (Client) → customer + New Subscription Booking (Staff) → staff/admin |
| Confirmed | Subscription Booking Confirmed (Client) → customer |
| Cancelled | Subscription Booking Cancelled (Client) → customer (with site phone/email) |
- Submit & Confirm → does not send submitted/pending; only sends confirmed.
- Admin Mute Notifications (Submit/Submit & Confirm/Confirm/Terminate/Cancel) → skips emails that would otherwise be sent; the lifecycle still completes.
- Sent after the status has persisted; notification side effects do not mutate the lifecycle.
- Placeholders:
,,,,,,, etc.
Real-world example: A parent books a package from the portal. → The parent knows the booking is pending confirmation, staff know there is a new booking to review. → The customer gets New Subscription Booking (Client), staff get (Staff); if admin uses Submit & Confirm, only Subscription Booking Confirmed (Client) is sent.
Summary
| Role | Does |
|---|---|
| Admin | Create/configure package, link term, manage enrollment (View/Booked Periods, terminate), track Billing Manager, handle invoices. |
| Staff | Manage add-ons/discounts for booked periods; Submit / Submit & Confirm with the Mute Notifications option. |
| Customer | Browse packages, choose range per permission, fill Step 2, submit booking (clash-checked), receive lifecycle notifications. |
Next: Core concepts.