Booking — Case thường gặp
Các tình huống thực tế và cách hệ thống phản ứng.
Double-booking (trùng lịch)
- Cùng attendee không được book cùng TermProduct trùng ngày/giờ.
- Check ở create, submit và confirm.
- Admin có thể bỏ qua bằng
IgnoreDoubleBooking = true. - Record type
Subscription/WaitingListkhông tính là conflict normal booking.
Ví dụ thực tế: Phụ huynh đặt 2 con vào cùng buổi sáng Thứ 2. → Tránh ghi nhầm cùng một trẻ hai lần. → Hệ thống chặn con thứ 2 ở bước submit, trừ khi admin bật
IgnoreDoubleBooking.
Chiều cao / cân nặng (measurement)
- Course có thể cấu hình ngưỡng height/weight. Attendee ngoài ngưỡng → selection invalid, chặn submit.
- Thiếu giá trị bắt buộc (vd weight) → submit fail cho selection đó.
- Admin override từng rule: tắt Height vẫn để Weight chặn, và ngược lại.
Ví dụ thực tế: Lớp bơi đặt ngưỡng cân nặng tối thiểu; trẻ chưa khai weight. → Đảm bảo trẻ đủ điều kiện an toàn trước khi vào lớp. → Submit fail cho selection đó tới khi nhập weight, hoặc admin tắt riêng rule Weight.
Booking Cut-off (chọn session quá khứ)
- Mặc định không chọn được session đã qua mốc cut-off.
- Admin tắt Booking Cut-off trong Booking Rule Options → chọn được session quá khứ (mọi category: Term Care, Holiday, Class).
Ví dụ thực tế: Trẻ đã đi học buổi Thứ 3 nhưng quên đăng ký, cần book bù. → Cho ops ghi nhận buổi đã diễn ra để tính phí/điểm danh. → Admin tắt Booking Cut-off, chọn lại session quá khứ đó rồi confirm.
Pay Later & timeout auto-cancel
- PayNow / Deposit / Direct Debit có thể arm timeout: quá hạn chưa thanh toán → tự hủy.
- PayLater không timeout nhưng phải qua validate eligibility lúc submit.
Ví dụ thực tế: Phụ huynh chọn Deposit rồi rời đi không thanh toán. → Tránh giữ chỗ vô thời hạn làm nghẽn capacity. → Hết hạn timeout, booking tự hủy, slot mở lại cho người khác.
Capacity
- Giới hạn theo
TermProduct.CapacityvàTermProgramSetCapacity(tuần giới hạn). ValidateCapacityForConfirmBookingchạy trước confirm.
Ví dụ thực tế: Lớp còn 1 chỗ, hai phụ huynh cùng bấm confirm gần như đồng thời. → Không cho vượt sĩ số lớp. →
ValidateCapacityForConfirmBookingchặn người confirm sau, báo hết chỗ.
Add-on capacity (bắt buộc kèm add-on)
- Add-on (vd bus route) có capacity riêng; order line chạm đủ → chặn confirm với
FULLY_ADDON_CAPACITY_BOOKING_FOUND, trừ khi admin bậtIgnoreDoubleBooking. - Khác với session capacity: đây là capacity của add-on đi kèm booking, không phải sĩ số session.
Ví dụ thực tế: Booking mới kèm tuyến bus đã đủ trẻ đăng ký. → Tránh nhận thêm trẻ vượt tải xe. → Confirm bị chặn ở bước build plan; admin bật
IgnoreDoubleBookingnếu cố ý cho phép.
Confirm chỉ đúng khi order ở trạng thái cho phép
- Chỉ
TypeId ∈ {Booking, TrialSession}vàStatusId ∈ {Submitted, Submitted_Change, Attendance_Approved, Quote}mới confirm được; các order khác làm confirm fail. Confirm_Booking→Approved,Confirm_Attendance→Attendance_Approved(bỏ qua Billing Difference),Confirm_Invoice→Quote.
Ví dụ thực tế: Admin bấm Confirm trên order
WaitingListhoặc booking đãCanceled. → Tránh tạo runtime booking từ trạng thái không hợp lệ. → Confirm bị chặn, booking không đổi trạng thái.
Quote → Accept
- Thay vì confirm ngay, có thể
GenerateQuotes(statusQuote) → kháchAcceptQuote(Accept) → confirm (Approved).
Ví dụ thực tế: Admin chốt chương trình holiday cho gia đình nhưng để họ tự duyệt giá. → Cho khách xem và đồng ý báo giá trước khi cam kết thanh toán. →
GenerateQuotesgửi báo giá, kháchAcceptQuote, sau đó mới confirm.
Cancel → credit note
- Cancel booking đã confirm: status →
Canceled, đảo invoice bằng credit note, deactivateTermAttendance— kể cả khi một số line trước đó đã rờiApproved.
Ví dụ thực tế: Gia đình hủy khóa đã đóng tiền và điểm danh. → Hoàn tiền đúng sổ sách và bỏ các buổi không còn hiệu lực. → Booking về
Canceled, hệ thống phát credit note đảo invoice và deactivateTermAttendance.
Stale attendance (điểm danh "mồ côi")
- Có quy trình dry-run phát hiện
TermAttendancecòn active nhưngTermBookingcha đãCanceled(trả về count + sample, không sửa dữ liệu) để ops sửa an toàn.
Ví dụ thực tế: Một lỗi cũ để lại điểm danh của booking đã hủy, gây sai báo cáo có mặt. → Phát hiện dữ liệu rác trước khi tự ý xóa. → Dry-run liệt kê count + vài bản ghi mẫu để ops kiểm tra rồi xử lý tay.
Combined edit (gộp booking)
- Category có
CombinedBookingOptionId = 1: edit một booking sẽ nạp các booking cùngActionLogIdxuyên course trong category. Bỏ một booking khỏi nhóm khi reconfirm → cancel + deactivate attendance của nó. Chi tiết: Combine booking rule.
Ví dụ thực tế: Phụ huynh đổi lịch một con vốn book chung nhóm gộp nhiều khóa. → Sửa cả nhóm đồng bộ thay vì lệch từng booking. → Edit một booking nạp các booking cùng
ActionLogId; bỏ một booking khỏi nhóm sẽ cancel + deactivate attendance của nó.
Confirm Attendance (Submit & Confirm Attendance)
- Submit xong → gọi confirm với action type
Confirm_Attendancengay → statusAttendance_Approved(chưa phải confirmed đầy đủ), không mở Billing Difference preview. - Submit thất bại, hoặc không trả đủ
TermBookingOrderIds→ báo lỗi, không confirm.
Ví dụ thực tế: Admin cần chốt điểm danh cho booking đã đi học nhưng chưa chốt tiền. → Tránh bắt xem chênh lệch tài chính vô nghĩa. →
Submit & Confirm Attendancesubmit rồi chốtAttendance_Approvedngay, không preview.
Edit booking đã confirm (Billing Difference)
Submit & Confirmtách 2 bước: submit (mute) → xem Billing Difference → bấm Confirm.- Submit trả về đủ
TermBookingOrderIdsđể preview & confirm chung (invariantINV-BOOK-21); preview/confirm dùng đúng set id đó, không lấy lại từ selection UI (invariantINV-BOOK-25). - Submit của edit bị mute server-side dù client gửi
muteNotification = false(invariantINV-BOOK-26); lựa chọn mute cuối cùng lấy ở popup confirm, gửi kèm request confirm. - Thứ tự UI: preview Billing Difference → popup xác nhận action → mới submit/confirm. Đóng preview → booking chưa confirm.
Ví dụ thực tế: Admin thêm 1 buổi vào booking đã confirm, khách cần biết phải trả thêm bao nhiêu. → Cho xem chênh lệch phí trước khi cam kết. → Submit (mute) hiện Billing Difference; admin xem rồi mới bấm Confirm để chốt.
Giữ điểm danh khi edit (roll call preserve)
- Edit confirm tạo lại
TermBookingLine+ thayTermAttendancevì giá/discount đổi → giữ roll call từ attendance cũ nếu nó cóRollCallStatusId > 0— kể cả khi bản cũ đã bị deactivate trong luồng. - Copy cả
RollCallHistory(action id, thời gian, signed-by, signature, absent reason, note); confirm retry không nhân đôi history. RollCallStatusId = 0(chưa điểm danh) → attendance mới bình thường, không copy. Session bị xóa/cancel → không copy roll call sang nơi khác.
Ví dụ thực tế: Booking đã điểm danh buổi Thứ 2 rồi admin sửa giá buổi đó, confirm tạo lại attendance. → Tránh mất dấu vết có mặt/ra về. → Attendance mới copy roll call + history từ bản cũ (invariant
INV-BOOK-27).
Submit & Confirm Attendance (admin)
- Admin Mode có action Submit & Confirm Attendance: submit trước, rồi gọi confirm bằng action type
Confirm_AttendancevớiTermBookingOrderIdssubmit trả về. - Kết quả booking ở
Attendance_Approved— chốt điểm danh, không confirm đầy đủ. - Không bị gate bởi Billing Difference (invariant
INV-BOOK-26). - Submit ok nhưng confirm attendance fail → báo lỗi để admin retry hoặc hoàn thành ở Booking Manager; booking vẫn ở
Submitted. Submit không trả vềTermBookingOrderIds→ báo lỗi, không gọi confirm.
Ví dụ thực tế: Lớp bơi đã diễn ra nhưng admin quên chốt buổi đầu, cần điểm danh ngay. → Không cần review chênh lệch phí vì action này không đổi tiền. →
Submit & Confirm Attendanceđưa booking vềAttendance_Approvedđể cán bộ điểm danh làm việc, không confirm đầy đủ.
Pending notification suppression (Submit & Confirm)
POST /BookingOrdersadmin mode vớiStatusId= Confirmed (Submit & Confirm) → không enqueue/ gửi pending-booking notification cho request đó.- Request submit không direct-confirm (booking còn pending) → pending-booking notification chạy như cũ.
- Đây là behavior backend-only: không đổi contract
POST /BookingOrders. - Mute Notifications (popup xác nhận admin) → suppress các job notification eligible của action:
- Submit → suppress submitted; Confirm → suppress confirmed.
- Submit & Confirm → submitted đã suppress sẵn (direct-confirm) + confirmed suppress.
- Cancel → suppress cancelled.
- Không chọn Mute → giữ nguyên hành vi notification hiện có.
Ví dụ thực tế: Admin
Submit & Confirmchốt nhanh hàng loạt nhưng không muốn spam phụ huynh. → Tránh email trạng thái trung gian không cần thiết. → Request direct-confirm không phát pending notification; nếu bật Mute Notifications, cả job confirmed cũng không được gửi.