Edit Booking: enabling / disabling Preview Billing Diff
When PreviewBillingDifferenceEnabled is on, the admin can review the billing change before confirming.
When the flag is off, or the booking is not eligible, the normal Edit Booking flow is used.
Quick glossary
| Term | Quick meaning | What is it for? |
|---|---|---|
TermBookingOrderIds | The official IDs of the edit after SubmitOrder | The canonical input for Preview and Confirm; do not replace them with the UI payload or TermBookingId. |
PreviewBillingDifference | Calculates the billing change | Reads persisted data, builds the result in memory, and does not write real data. |
Billing Difference | The total amount that will increase or decrease | + usually means more to collect; - means a reduction/credit; the total is by billing scope. |
Billing context | The shared data group for one billing scope | Includes BillingId, AccountId, and BusinessUnitId; orders in one Preview must belong to the same group. |
Original transaction | An old invoice/credit note used as the comparison baseline | Shows the current billing position so the increase, reduction, or credit can be calculated. |
PreviewSnapshotToken | A seal for the Preview result | Confirm sends it back to check that the result the admin reviewed still matches; missing or invalid token blocks writes. This token does not grant permission. |
PREVIEW_BILLING_DIFF_STALE | The Preview is no longer current | The booking, promo, setting, or option changed; Preview must run again instead of auto-confirming. |
muteNotification | Temporarily suppresses the notification on Submit | The new edit waits for admin review; notifications and side effects run after Confirm. |
1. Quick comparison
| What to know | Preview on | Preview off / not eligible |
|---|---|---|
| Flow | SubmitOrder → PreviewBillingDifference → ConfirmOrder | SubmitOrder → ConfirmOrder |
| Billing review | Review the invoice increase/credit reduction before Confirm | Review the result after Confirm |
| DB writes before Confirm | Preview is read-only; no writes | No Preview step |
| Confirm | Requires the same IDs/options and a valid PreviewSnapshotToken | Uses IDs/options; no token required |
| If the admin disagrees | Edit again or open the pending booking | Return to Edit Booking if needed |
Real-world example: The admin adds 2 sessions. → With Preview on: review how much the invoice will increase. → With Preview off: confirm first, then review the result.
2. When does Preview appear?
| Situation | Preview? | Behavior |
|---|---|---|
| Confirmed booking edit, meets the conditions below, flag on | Yes | Submit → Preview → Confirm |
| Confirmed booking edit, flag off | No | Confirm through the existing flow |
| Booking edit misses a condition below | No | Go directly to the confirmation popup when the action is valid |
| Admin New Booking | No | Keep Submit & Confirm |
Submit & Confirm Attendance | No | Submit, then confirm attendance |
| Cancel / terminate / transfer / rollover | No | Use the separate lifecycle flow |
| Bulk with an edit or mixed new/edit | No bypass | Reject the whole batch; process each booking edit separately |
Preview is not a separate button. It is opened only from the applicable Submit/Confirm action.
2.1. Conditions for Preview to run
Preview runs only when all of these condition groups pass:
| Group | Plain-language condition |
|---|---|
| Flow | Flag on; an admin is editing an existing booking; not New Booking, Attendance, or a lifecycle action. |
| Order | The edit was submitted; the order is active; backend returned TermBookingOrderIds; the status is Submitted or Submitted_Change; at most 500 IDs per request. |
| Original booking | Each order points to an active original booking whose status is Attendance_Approved, Quote, or Approved; Preview is unavailable for other statuses. |
| Billing context | BillingId, AccountId, BusinessUnitId, AttendeeId, and TermProgramSetId are present; all orders share the same billing/account/BU context. |
| Permission & scope | The user has Booking Manager permission; every order is inside the BU/account/enterprise scope the admin can access. |
| Billing data | An old invoice/credit note exists for comparison, along with Business Unit invoice settings and a default tax rate; each line/extra has a booking/order link. |
Preview has stricter conditions than Confirm: Confirm may continue without Preview only when policy explicitly allows it.
If order IDs are missing, scope is wrong, context is mixed/incomplete, or the billing result cannot be calculated exactly → return a structured error and never show a guessed amount.
Real-world example: An admin edits one session in a confirmed booking. → Submit creates an order with the same billing context and returns
TermBookingOrderIds. → Preview opens; a new booking or a booking with no old invoice/credit note may direct-confirm only when policy allows it.
3. Data flow
3.1. Preview on
3.2. Preview off
4. Four milestones to remember
| Milestone | Both flows | Preview on only |
|---|---|---|
| 1. Edit & validate | Select sessions/extras/discounts; check permission, scope, and booking state | — |
| 2. Submit | Create or update the pending TermBookingOrder; backend returns complete TermBookingOrderIds | muteNotification = true |
| 3. Review billing | — | PreviewBillingDifference is read-only → returns Billing Difference and PreviewSnapshotToken |
| 4. Confirm & persist | Use order IDs; write booking/billing in one transaction | Validate the token before writing; invalid token → PREVIEW_BILLING_DIFF_STALE |
| 5. After commit | Refresh UI, history, notification, scheduler, and external event | Same |
5. Data tables used
Legend: READ means read only · WRITE creates/updates data · — not involved.
| Table / data group | What is it for? | Submit | Preview | Confirm |
|---|---|---|---|---|
TermBookingOrder + line/extra/discount | Pending edit and content used for billing calculation | WRITE | READ | READ |
Billing | Billing scope and payment context | WRITE | READ | WRITE |
TermBooking + line/extra/discount | Current booking used for comparison and result persistence | READ | READ | WRITE |
TermAttendance | Attendance used to build the confirmation plan | — | READ | WRITE |
Invoice + lines | Current and projected invoice | — | READ | WRITE |
CreditNote + lines | Projected reduction/refund | — | READ | WRITE |
Discount + DiscountApplication | Eligibility check and discount application | READ / WRITE | READ | READ / WRITE |
BusinessUnitSetting + invoice settings | Tax, currency, frequency, and split rule | READ | READ | READ |
| Invoice/credit-note logs | Link booking to finance records | — | READ | WRITE |
| Scheduler / history / notification | Side effects after Confirm | — | — | WRITE |
Important: PreviewBillingDifference may read current data and build the projection in memory. Preview does not write TermBooking, Billing, Invoice, CreditNote, attendance, scheduler, history, notification, or call SaveChanges.
6. What does Preview return?
| Field / displayed part | Meaning |
|---|---|
Summary.Difference | Net change for the billing scope; + means an increase, - means a reduction/credit |
Current net billed | Current amount after existing credit notes |
Projected net billed | Current net billed + Difference |
Paid to date | Current total Invoice.AmountPaid; not divided by attendee |
Open invoice balance | Current total Invoice.AmountDue |
AttendeeBreakdowns | Breakdown for checking; not a separate per-attendee calculation |
Formula:
Difference = new invoice - new credit note - scheduled-delete invoiceinvoice scheduled-delete is an old invoice marked for deletion/reduction when Confirm runs.
Other booking groups: another booking with the sameBillingId.Shared / Unallocated: an attendee cannot be determined.- The UI uses
Summary.Differencedirectly; it does not recalculate it from the transaction list.
| Case | Result when Preview is on |
|---|---|
| Add a session / extra | See the invoice increase before Confirm |
| Remove an invoiced session | See the credit/reduction before Confirm |
| Change discount/promo | Recalculate using the shared rules |
| No billing change | No work; do not create a fake $0 transaction |
| Multiple attendees | Total remains by billing scope; the amount is not split evenly |
Real-world example: Current invoice is
$125, existing credit note is$1.50. →Current net billedis$123.50. Do not useDifferenceas the price for each attendee.
7. Errors and important cases
| Case | Behavior |
|---|---|
| Submit does not return complete IDs | Stop; do not Preview or Confirm |
IDs are missing, wrong scope, mixed context, or not Submitted | Structured error; do not fall back to the UI payload |
| Accurate projection cannot be built | Do not show a guessed amount; block or fall back according to policy |
PREVIEW_BILLING_DIFF_STALE | Do not auto-confirm; run Preview again |
| Admin disagrees | Edit this booking again or open the pending Booking Manager |
| Temporary Preview error | Retry or open the pending booking |
| Confirm fails during persistence | Roll back booking/billing in the transaction |
| Bulk with an edit or mixed new/edit | Reject the whole batch with PREVIEW_BILLING_DIFF_BATCH_EDIT_NOT_SUPPORTED |
Preview error INELIGIBLE_ORDER / NO_ORIGINAL_TRANSACTION | Allow direct-confirm only when the flow has no preview token; if already reviewed with a token, return PREVIEW_BILLING_DIFF_STALE and never silently bypass |
8. Short FAQ
| Question | Answer |
|---|---|
| Does Preview write real invoices/credit notes? | No. Only Confirm writes them. |
| Can an already-paid booking be previewed? | Yes, if the data is sufficient; it may produce a credit-note impact. |
| Does Preview split money by attendee? | No. The total is by billing scope; attendee rows are explanatory. |
| Does New Booking / Attendance have Preview? | No. Keep the current separate flow. |
| Why can Confirm work when Preview cannot? | Preview needs an exact baseline and context; Confirm may skip Preview only for policy-approved cases. |
| Should Preview and Confirm produce the same number? | Yes, with the same IDs/options and no state change; generated IDs or timestamps may differ normally. |
Real-world example: Preview reports
+$40, but invoice settings change before Confirm. → The token is stale. → Do not write the old$40; run Preview again and confirm the new amount.
9. One sentence
Preview on: Submit → review the difference → Confirm with the token → persist.
Preview off: Submit → Confirm directly.