using System.ComponentModel.DataAnnotations; namespace Fitness_core_BE.DTOs.Booking { public class CreateMemberBookingRequest { [Required] public Guid FacilitySessionId { get; set; } } public class CreateGuestBookingRequest { [Required] public Guid FacilitySessionId { get; set; } [Required] public string GuestName { get; set; } = string.Empty; [Required] public string GuestPhone { get; set; } = string.Empty; /// Optional link to an existing registered customer (TenantCustomerLinkId) when /// staff recognizes the walk-in as an already-registered member -- purely for /// identification/auto-fill, doesn't change payment/membership handling at all. public Guid? CustomerId { get; set; } } public class CreateAdhocBookingRequest { [Required] public Guid FacilityId { get; set; } [Required] public DateTime StartTime { get; set; } [Required, Range(1, int.MaxValue, ErrorMessage = "DurationMinutes must be at least 1")] public int DurationMinutes { get; set; } public int? PartySize { get; set; } } public class CreateGuestAdhocBookingRequest { [Required] public Guid FacilityId { get; set; } [Required] public DateTime StartTime { get; set; } [Required, Range(1, int.MaxValue, ErrorMessage = "DurationMinutes must be at least 1")] public int DurationMinutes { get; set; } [Required] public string GuestName { get; set; } = string.Empty; [Required] public string GuestPhone { get; set; } = string.Empty; public int? PartySize { get; set; } /// Overrides the facility's own PricePerHour for this booking's charge only -- /// the FE pre-fills this from the facility but lets staff adjust it. [Range(typeof(decimal), "0", "79228162514264337593543950335", ErrorMessage = "PricePerHour cannot be negative")] public decimal? PricePerHour { get; set; } /// Optional link to an existing registered customer -- see /// CreateGuestBookingRequest.CustomerId. public Guid? CustomerId { get; set; } } public class MarkGuestBookingPaidRequest { [Required] public Guid BookingId { get; set; } [Required] [Range(0.01, double.MaxValue, ErrorMessage = "AmountCharged must be greater than zero")] public decimal AmountCharged { get; set; } /// "Cash" | "Bank". Defaults to "Cash" if omitted. public string? PaymentMethod { get; set; } } /// Body for POST .../complete. Only required when the booking is a guest booking /// still Unpaid -- see BookingService.CompleteBooking. Ignored otherwise (member bookings, /// or a guest booking already Paid). public class CompleteBookingRequest { public bool? MarkPaid { get; set; } public decimal? AmountCollected { get; set; } /// "Cash" | "Bank". Defaults to "Cash" if omitted. public string? PaymentMethod { get; set; } } public class CheckInBookingRequest { [Required] public string OtpCode { get; set; } = string.Empty; /// Picked from the club's managed RFID tag pool (GET api/client/rfid-tags? /// status=Available) -- never free-typed. Required in practice for an AdHoc booking's /// check-in; optional for Scheduled bookings that don't hand out a physical tag. public Guid? RfidTagId { get; set; } } public class CancelBookingRequest { [Required] public Guid BookingId { get; set; } } public class ReassignBookingRequest { public string? GuestName { get; set; } public string? GuestPhone { get; set; } } /// Exactly one shape applies, matching the booking's current BookingMode: AdHoc /// bookings move within the SAME facility to a new StartTime/DurationMinutes; Scheduled /// bookings move to a different FacilitySession (also on the same facility). Only allowed /// while the booking is still Confirmed, and only onto a slot with room -- re-runs the same /// availability check as creation, excluding the booking's own current slot. public class RescheduleBookingRequest { // AdHoc reschedule. public DateTime? StartTime { get; set; } [Range(1, int.MaxValue, ErrorMessage = "DurationMinutes must be at least 1")] public int? DurationMinutes { get; set; } // Scheduled reschedule. public Guid? FacilitySessionId { get; set; } } }