using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace Fitness_core_BE.Models { /// A prepaid time balance on an RFID card, deducted by actual use via a tap-in/ /// tap-out swipe pattern (a 1-hour visit deducts 60 minutes, a 15-minute visit deducts 15 -- /// see ActiveSessionStartedAt) — separate from Booking's per-session OTP flow. Can belong to /// a member (FKCustomerId set, e.g. an add-on to their plan) or be sold standalone to a /// walk-in against just the RFID tag. public class TimeBankCard { [Key] public Guid TimeBankCardId { get; set; } public Guid FKClientId { get; set; } [ForeignKey(nameof(FKClientId))] public Client Client { get; set; } // Tenant-bucket entity: holds a TenantCustomerLinkId, not the central Customer.CusId // directly -- see Models/TenantCustomerLink.cs. Null for a card sold to a walk-in with // no membership at all. public Guid? FKCustomerId { get; set; } [ForeignKey(nameof(FKCustomerId))] public TenantCustomerLink? TenantCustomerLink { get; set; } [MaxLength(64)] public string RfidTagId { get; set; } = string.Empty; public int TotalMinutesPurchased { get; set; } public int MinutesRemaining { get; set; } public decimal AmountPaid { get; set; } = 0m; public Guid? FKPaymentTransactionId { get; set; } [ForeignKey(nameof(FKPaymentTransactionId))] public PaymentTransaction? PaymentTransaction { get; set; } public DateTime PurchasedAt { get; set; } = DateTime.UtcNow; /// Null = balance never expires (spend it whenever); business can still set one. public DateTime? ExpiresAt { get; set; } public bool IsActive { get; set; } = true; public DateTime CreatedAt { get; set; } = DateTime.UtcNow; // Tap-in/tap-out state: null = not currently on the floor anywhere. A swipe with this // null starts a session (tap-in, no deduction yet); a swipe with this set ends it // (tap-out) and deducts the elapsed minutes. One open session per card at a time -- // a second tap-in without a matching tap-out first is rejected by the service, not // silently overwritten, so a lost/forgotten tap-out surfaces instead of losing time. public DateTime? ActiveSessionStartedAt { get; set; } public Guid? ActiveSessionFacilityId { get; set; } [ForeignKey(nameof(ActiveSessionFacilityId))] public Facility? ActiveSessionFacility { get; set; } public virtual ICollection UsageLogs { get; set; } } }