using Ophelias.Managers; using System.Data.SQLite; namespace Ophelias.Models { internal class Reservation { /* * The reservation class is comprised of many pieces of information. For details on the * Guest and Transaction components, see Guest and Transaction classes. * * Reservations are comprised of the following: * * ID * Identifies the reservation * * RoomNum * Indicates what room the guest is staying/ stayed in * * Guest * See Guest.cs model class * * Transaction * See Transaction.cs model class * * IsNoShow * Boolean to indicate if someone is a no-show/ does not show up to their * scheduled reservation * * Type * The type of reservation made (Conventional, Prepaid, Incentive, 60-day/ Advance) * * Status * Indicates if the reservation is active, changed, cancelled, or ended * * CreationDate * The date the reservation was created * * StartDate * The date the reservation is scheduled to being * * EndDate * The date the reservation is scheduled to end * * CheckIn * Reflects when the guest checked in, currently mirrors StartDate when set * * CheckOut * Reflects when the guest checked out, currently mirrors EndDate when set * * DateChanged * The date the reservation was updated/ changed */ internal int Id; internal int? RoomNum; internal Guest Guest; internal Transaction Transaction; internal bool IsNoShow; internal ReservationType Type; internal ReservationStatus Status; internal DateTime CreationDate; internal DateTime StartDate; internal DateTime EndDate; internal DateTime? CheckIn; internal DateTime? CheckOut; internal DateTime? DateChanged; internal Reservation(Guest Guest, ReservationType Type, DateTime CreationDate, DateTime StartDate, DateTime EndDate, ReservationStatus Status = ReservationStatus.Active, bool IsNoShow = false, DateTime? CheckIn = null, DateTime? CheckOut = null, DateTime? DateChanged = null, int? RoomNum = null) { /* * Creates a new reservation assuming it never existed in the first place. * * Upon creating a reservation, this function will set the appropriate fees * based on the type of reservation. See TxFunctions in the transaction class * for the specific fee multiplier values. The base rate is then retrieved for * the current date if a new one was set for that date, otherwise the base rate * used is whatever the default last was. We do not tether the rate to an ID * since the rate only changes when the reservation is tweaked. This information * is then passed off to create a new Transaction. See the Transaction class for * more information. * * Once a new transaction has been created, a database connection is opened to create * a new reservation and the ID generated is returned back. This value is then set * to the reservation and a new instance is returned. */ int Id; double Multiplier; switch (Type) // Determines the appropriate fee multiplier to set { case ReservationType.Conventional: Multiplier = TxFunctions.ConventionalFee; break; case ReservationType.Prepaid: Multiplier = TxFunctions.PrepaidFee; break; case ReservationType.Incentive: Multiplier = TxFunctions.IncentiveFee(StartDate, EndDate); break; case ReservationType.SixtyDayAdvance: Multiplier = TxFunctions.SixtyDayFee; break; default: throw new NotImplementedException(); } double? BaseRate = Hotel.GetBaseRate(); // Checks to see if there is a new base rate and uses the rate returned, old default or new default if (BaseRate == null) // Exists for the unlikely situation a reservation is made on a null rate { throw new NotImplementedException(); } Transaction Transaction = new( // Creates a new transaction, see the Transaction class for more details on TxFunctions or trnsaction itself Rate: (double)BaseRate, Owed: TxFunctions.CalculateOwed((double)BaseRate, (int)(EndDate.Date - StartDate.Date).TotalDays, Multiplier), Multiplier: Multiplier, PayBy: TxFunctions.GetPayByDate(Type, StartDate, EndDate) ); using (Database Manager = new()) // Creates a new database connection { using (SQLiteCommand cmd = Manager.con.CreateCommand()) // Creates a new command that will be executed in the database { if (RoomNum != null) { this.RoomNum = RoomNum; } /* * The folowing is a query with parameters that are set based off certain conditions, * such as if the value exists. */ cmd.CommandText = "INSERT INTO reservations (RoomNum, GuestID, TransactionID, IsNoShow, Type, Status, CreationDate, StartDate, EndDate, CheckIn, CheckOut, DateChanged) " + "VALUES (@RoomNum, @GuestID, @TransactionID, @IsNoShow, @Type, @Status, @CreationDate, @StartDate, @EndDate, @CheckIn, @CheckOut, @DateChanged);"; cmd.Parameters.AddWithValue("@RoomNum", RoomNum); cmd.Parameters.AddWithValue("@GuestID", Guest.Id); cmd.Parameters.AddWithValue("@TransactionID", Transaction.Id); cmd.Parameters.AddWithValue("@IsNoShow", Convert.ToInt32(IsNoShow)); cmd.Parameters.AddWithValue("@Type", (int)Type); cmd.Parameters.AddWithValue("@Status", (int)Status); cmd.Parameters.AddWithValue("@CreationDate", CreationDate.ToString("yyyy-MM-dd")); cmd.Parameters.AddWithValue("@StartDate", StartDate.ToString("yyyy-MM-dd")); cmd.Parameters.AddWithValue("@EndDate", EndDate.ToString("yyyy-MM-dd")); if (CheckIn.HasValue) { cmd.Parameters.AddWithValue("@CheckIn", CheckIn.Value.ToString("yyyy-MM-dd")); } else { cmd.Parameters.AddWithValue("@CheckIn", CheckIn); } if (CheckOut.HasValue) { cmd.Parameters.AddWithValue("@CheckOut", CheckOut.Value.ToString("yyyy-MM-dd")); } else { cmd.Parameters.AddWithValue("@CheckOut", CheckOut); } if (DateChanged.HasValue) { cmd.Parameters.AddWithValue("@DateChanged", DateChanged.Value.ToString("yyyy-MM-dd")); } else { cmd.Parameters.AddWithValue("@DateChanged", DateChanged); } cmd.ExecuteNonQuery(); } Id = (int)Manager.con.LastInsertRowId; // Sets the ID returned by the query } this.Id = Id; this.RoomNum = RoomNum; this.Guest = Guest; this.Transaction = Transaction; this.IsNoShow = IsNoShow; this.Type = Type; this.Status = Status; this.CreationDate = CreationDate; this.StartDate = StartDate; this.EndDate = EndDate; this.CheckIn = CheckIn; this.CheckOut = CheckOut; this.DateChanged = DateChanged; } internal Reservation(int Id, Guest Guest, Transaction Transaction, ReservationType Type, ReservationStatus Status, DateTime CreationDate, DateTime StartDate, DateTime EndDate, bool IsNoShow = false, DateTime? CheckIn = null, DateTime? CheckOut = null, DateTime? DateChanged = null, int? RoomNum = null) { /* * This creates and returns a reservation assuming it already existed * as an ID is required if the reservation exists in the system. */ this.Id = Id; this.RoomNum = RoomNum; this.Guest = Guest; this.Transaction = Transaction; this.IsNoShow = IsNoShow; this.Type = Type; this.Status = Status; this.CreationDate = CreationDate; this.StartDate = StartDate; this.EndDate = EndDate; this.CheckIn = CheckIn; this.CheckOut = CheckOut; this.DateChanged = DateChanged; } internal void ChangeReservationDates(DateTime StartDate, DateTime EndDate) { /* * Change Reservation Dates allows for the manipulation of start and end dates. * These changes saved to the reservation and reflected in the database. * It also makes a call to update the transaction fees. See Transaction class for * details on this. A new rate and multiplier are set also since reservation changes * come at the cost of paying based on the most recent base rate and 110% multipler. */ this.StartDate = StartDate; this.EndDate = EndDate; DateChanged = DateTime.Now.Date; using (Database Manager = new()) // Creates a new database connection { using (SQLiteCommand cmd = Manager.con.CreateCommand()) // Creates a new command that will be executed in the database { string? query = QueryBuilder.UpdateReservation(Id: Id, Status: ReservationStatus.Changed, StartDate: this.StartDate, EndDate: this.EndDate, DateChanged: DateChanged); // Builds a new query string with parameters if (query == null) { throw new Exception(); } cmd.CommandText = query; cmd.Parameters.AddWithValue("@ID", Id); cmd.Parameters.AddWithValue("@Status", Status); cmd.Parameters.AddWithValue("@StartDate", StartDate.ToString("yyyy-MM-dd")); cmd.Parameters.AddWithValue("@EndDate", EndDate.ToString("yyyy-MM-dd")); cmd.Parameters.AddWithValue("@DateChanged", DateChanged.Value.ToString("yyyy-MM-dd")); cmd.ExecuteNonQuery(); } } double? BaseRate = Hotel.GetBaseRate(); // Checks for the most recent rate to replace the old rate if (BaseRate == null) { throw new ArgumentNullException(nameof(BaseRate)); } Transaction.UpdateTransactionFees((double)BaseRate, TxFunctions.Changed, TxFunctions.GetPayByDate(Type, this.StartDate, this.EndDate)); // Creates a new transaction } internal void CancelReservation() { /* * Cancel Reservation will cancel the existing reservation and issue penalties * if they apply. Specifically if the reservation type is conventional, incentive, * or the reservation is past due and the right criteria are met, the transaction * class calls the pay function and the accounts are charged. See Transaction.Pay() * for more details. The reservation is also set to cancelled in the database. */ DateTime _DateChanged = DateTime.Now.Date; using (Database Manager = new()) // Creates a new database connection { using (SQLiteCommand cmd = Manager.con.CreateCommand()) // Creates a new command that will be executed in the database { string? query = QueryBuilder.UpdateReservation(Id: Id, Status: ReservationStatus.Cancelled, DateChanged: _DateChanged); // Builds a new query string with parameters if (query == null) { throw new Exception(); } Status = ReservationStatus.Cancelled; DateChanged = _DateChanged; cmd.CommandText = query; cmd.Parameters.AddWithValue("@ID", Id); cmd.Parameters.AddWithValue("@Status", Status); cmd.Parameters.AddWithValue("@DateChanged", DateChanged.Value.ToString("yyyy-MM-dd")); cmd.ExecuteNonQuery(); } } if (Type == ReservationType.Conventional && _DateChanged.Date >= StartDate.AddDays(-3).Date) // Charge conventional reservations cancelled three or less days of stay { Transaction.Pay(Transaction.Owed, Guest.CreditCard); } else if (Type == ReservationType.Incentive && _DateChanged.Date >= StartDate.AddDays(-3).Date) // Charge incentive based on the same policy as conventional { Transaction.Pay(Transaction.Owed, Guest.CreditCard); } else if (_DateChanged.Date > StartDate.Date) // Charge based on no-show { Transaction.Pay(Transaction.Owed, Guest.CreditCard); } } } internal enum ReservationStatus // Represets numerical values as words { Active, Changed, Cancelled, Ended, } internal enum ReservationType // Represents numerical values as words { Conventional, Prepaid, SixtyDayAdvance, Incentive, } }