Booking — Luồng xử lý trong code
Trang này trace từ API → service → validation cho normal booking. File chính:
- Controller:
Tux/src/Tux.Api/Controllers/Consumer/ConsumerBookingController.cs - Service:
Tux/src/Services/Tux.Service/BookingService.cs - Helper:
Tux/src/Services/Tux.Service/Helpers/BookingHelper.cs
Tổng thể
Luồng 1 — Create order (giỏ hàng)
- API:
CreateBookingOrder. - Tạo
TermBookingOrder+TermBookingOrderLine(statusCreated). - Validate: attendee/term product hợp lệ, org setting, measurement (chiều cao/cân nặng) nếu bật, double-booking (trừ khi
IgnoreDoubleBooking). - Chưa tạo Billing.
Luồng 2 — Submit
- API:
SubmitBookingOrders→BookingService.SubmitBookingAsync. - Chỉ chấp nhận order type
BookingvàTrialSession. - Tạo
Billing(tổng hợp tài chính); validate Pay Later eligibility (quaBookingHelper). - Có thể arm timeout auto-cancel nếu payment option yêu cầu (PayNow/Deposit/Direct Debit).
- Double-booking check lần cuối. Status →
Submitted. Chưa tạo Invoice. - Trả về đủ
TermBookingOrderIdsđể confirm sau (đầy đủ hoặc attendance) không cần suy đoán ở UI.
Luồng 3 — Billing Difference preview
- Entry chính:
PreviewBillingDifference→ConsumerBookingController→BillingService. - Backend kiểm tra canonical order IDs, permission, scope và billing context; sau đó dùng shared
BookingConfirmationPlanvà financial rules với Confirm. - Preview là read-only, trả
Difference, projected transaction data, breakdown vàPreviewSnapshotToken; không gọi writer hoặcSaveChanges. - Confirm chuẩn bị lại kết quả, kiểm tra token trong transaction rồi persist; feature tắt hoặc booking không đủ điều kiện thì bỏ qua Preview/token theo policy.
Chi tiết từng file, điều kiện và error code nằm ở Code flow Preview Billing Diff.
Luồng 3b — Bulk Confirm trong Booking Manager
- UI:
BatchActionToolbargom các row được chọn rồi gọiBatchActionInQueue. - Selection chỉ gồm booking mới → giữ bulk
Confirm_Bookingvà queue như flow hiện có. - Selection có edit hoặc mixed new/edit → UI dừng trước khi gọi API, yêu cầu confirm từng booking group qua preview-first flow.
- Backend
BookingService.BatchActionInQueueAsynckiểm tra lạiTermBookingId,editOrderIdlineage/action và trảPREVIEW_BILLING_DIFF_BATCH_EDIT_NOT_SUPPORTEDtrước khi tạo lock hoặc scheduler. Confirm_Attendancekhông đi qua billing guard và vẫn queue bình thường.
Ví dụ thực tế: Admin chọn đồng thời một booking mới và một edit booking trong Booking Manager. → Tránh queue một phần mà bỏ qua billing review. → Toàn bộ selection bị từ chối; booking mới không bị lock, còn edit booking được confirm riêng qua Preview.
Luồng 4 — Confirm / Quote
- API:
ConfirmBookingOrders→BookingService.ConfirmBookingAsync(hoặcGenerateQuotesAsync/AcceptQuoteAsync). - Tạo
TermBookingtừTermBookingOrder; copy Line/Extra/Discount. - Áp discount, tính tổng (xem Discount rule).
- Tạo
TermAttendancecho từng session; trigger billing sinh Invoice. - Status →
Approved(hoặcAttendance_Approved, hoặcQuote). - Action type
Confirm_Attendance(1050) → chỉ chốt điểm danh, statusAttendance_Approved, không confirm đầy đủ; dùng choSubmit & Confirm Attendancecủa admin, không mở Billing Difference. - Edited booking: confirm build một
BookingConfirmationPlanchung từTermBookingOrderIdstrước khi áp side-effect thật (invariantINV-BOOK-23).BookingConfirmationPlanlà projection source of truth order → booking (header/line/extra/ discount); code preview không nhân bản thuật toán projection này.- Edit confirm tạo lại line + thay
TermAttendancevì giá/discount đổi → giữ roll call cũ (status, giờ, sign-in/out,RollCallHistory) khi attendance cũ cóRollCallStatusId > 0(invariantINV-BOOK-27); retry không nhân đôi history.
Luồng Subscription Enrichment trong Booking
Đây là đường runtime của Subscription Booking, không phải CreateBookingOrder của normal booking:
ConsumerEnrollmentnhận selection-only Enrichment và lưu pattern theo ngày.- Preview/submit/confirm resolve cùng
TermProducteffective, closure-day và occurrence date. EnrollmentService.GenerateBookingFromEnrollmenttạo mộtTermBookingLinecó giá/item cho mỗi occurrence và tạo attendance tương ứng.- Booking Billing/Reconciliation xử lý các line đó;
SubscriptionBillingServicechỉ xử lý base schedule/add-on củaEnrollmentBillingSchedule. - Replay dùng operation/semantic-key guard; không tạo duplicate active line hoặc duplicate charge.
Ví dụ thực tế: Worker confirm chạy lại cùng operation sau timeout. → Resolver thấy key Booking + TermProduct + Date đã tồn tại. → Không thêm line/attendance thứ hai và tổng Booking không tăng.
Luồng 5 — Cancel
- API:
DeleteBookingOrdersAsync→BookingService.CancelBookingAsync. - Status →
Canceled; đảo invoice bằng credit note; deactivateTermAttendance(kể cả khi một số line trước đó đã rờiApproved).
Validation chính
| Loại | Ở đâu |
|---|---|
| Capacity | TermProduct.Capacity, TermProgramSetCapacity; check ở create/submit/confirm. |
| Double-booking | So attendee × session trùng ngày/giờ; bypass bằng IgnoreDoubleBooking. |
| Measurement | Chiều cao/cân nặng vs cấu hình course; admin override từng rule. |
| Lock & pending | Booking locked / có pending order → chặn edit. |
| Discount eligibility | DiscountEligibilityService + BookingHelper.ApplyDiscount. |
Calendar và special-day flow
- Calendar wrapper map event → click handler; handler mở read-only detail popup và cancel mọi quick-info, editor, alert,
+N morepopup của Syncfusion. Time formatter dùng lại logic của tile. - Special-day matching group theo
sessionGroupKey, sau đó match product + time slot để tránh gộp sai; Tuke loại session đặc biệt khỏi booking surface theo trạng thái không bookable.
Ví dụ thực tế: Click event khi popup trước đó còn mở. → Nội dung chuyển toàn bộ sang event mới, không giữ attendee/time của event cũ; click empty cell không tạo popup.
Tiếp theo: Discount rule.