Files
ophelias-oasis/OpheliasOasis/Managers/Hotel.cs
雲華 0a5fa3e402 Updateed some formatting and bug fixes
Fixed inconsistencies in queries that would result in errors because
the parameters were missing. Updating a guest is an example that had
this issue. After checking parameters should all be supplied where
needed.
2022-04-17 18:55:38 -04:00

1153 lines
60 KiB
C#

using Ophelias.Models;
using System.Data.SQLite;
namespace Ophelias.Managers
{
internal static class Hotel
{
/*
* This class is a large collection of SQL queries that did not belong
* on a specific model. As a result they are viewed as functions of the "Hotel".
* For details on what each does, see their docstrings. All queries here are
* written using parameters to avoid SQL injection.
*/
internal static (List<(DateTime, int, string, string)>, List<int>) GetDailyOccupancy()
{
/*
* This function gets the daily occupancies by joining the reservation table
* with the guests and rooms table. It looks for where the current date is between
* any active/ changed reservation's, that has been checked in, start and end date.
* The query is then put in ascending order, or, organized by room number.
*/
List<int> previousOccupancies = new();
List<(DateTime, int, string, string)> currentOccupancies = new();
using (Database Manager = new()) // Open a new database connection
{
using SQLiteTransaction Transaction = Manager.con.BeginTransaction(); // Being a new SQL transaction
using (SQLiteCommand cmd = Manager.con.CreateCommand()) // Create a new command to execute
{
cmd.CommandText = "SELECT RoomNum, Lname, Fname, EndDate FROM reservations " +
"INNER JOIN guests ON reservations.GuestID = guests.ID " +
"INNER JOIN rooms ON reservations.RoomNum = rooms.ID " +
"WHERE (DATE(@Date) BETWEEN StartDate AND EndDate) AND Status IN (@Status1,@Status2) AND CheckIn IS NOT NULL " +
"ORDER BY RoomNum ASC;";
cmd.Parameters.AddWithValue("@Date", DateTime.Now.Date.ToString("yyyy-MM-dd"));
cmd.Parameters.AddWithValue("@Status1", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@Status2", (int)ReservationStatus.Changed);
using SQLiteDataReader reader = cmd.ExecuteReader(); // Create a new reader to read the SQL data
while (reader.Read())
{
currentOccupancies.Add((reader.GetDateTime(3), reader.GetInt32(0), reader.GetString(1), reader.GetString(2)));
}
}
using (SQLiteCommand cmd = Manager.con.CreateCommand()) // Create a new command to execute
{
cmd.CommandText = "SELECT RoomNum FROM reservations " +
"INNER JOIN guests ON reservations.GuestID = guests.ID " +
"INNER JOIN rooms ON reservations.RoomNum = rooms.ID " +
"WHERE DATE (DATE(@Date) BETWEEN StartDate AND EndDate) AND Status IN (@Status1);";
cmd.Parameters.AddWithValue("@Date", DateTime.Now.AddDays(-1).Date.ToString("yyyy-MM-dd"));
cmd.Parameters.AddWithValue("@Status1", (int)ReservationStatus.Ended);
using SQLiteDataReader reader = cmd.ExecuteReader(); // Create a new reader to read the SQL data
while (reader.Read())
{
foreach (var item in reader.GetValues())
{
if (item.GetType().Equals(typeof(int)))
previousOccupancies.Add((int)item);
}
}
}
Transaction.Commit(); // Commit the transaction changes if any made
}
return (currentOccupancies, previousOccupancies);
}
internal static List<Reservation> GetDailyArrivals()
{
/*
* This function queries for daily arrivals. A daily arrival is considered to be someone
* that arrives on the current date and has an active or changed reservation status.
* Using these conditions, the transaction and guest table are joined and then the
* data is ordered by the guests last name in ascending order.
*/
List<Reservation> reservations = new();
using (Database Manager = new()) // Open a new database connection
{
using SQLiteCommand cmd = Manager.con.CreateCommand(); // Create a new command to execute
cmd.CommandText = "SELECT * FROM reservations " +
"INNER JOIN transactions ON reservations.TransactionID = transactions.ID " +
"INNER JOIN guests ON reservations.GuestID = guests.ID " +
"WHERE DATE (@Date) = StartDate AND Status IN (@Status1,@Status2)" +
"ORDER BY Lname ASC;";
cmd.Parameters.AddWithValue("@Date", DateTime.Now.Date.ToString("yyyy-MM-dd"));
cmd.Parameters.AddWithValue("@Status1", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@Status2", (int)ReservationStatus.Changed);
using SQLiteDataReader reader = cmd.ExecuteReader(); // Create a new reader to read the SQL data
while (reader.Read())
{
/*
* Since we cannot get by string keys, each column is represented by a numerical value
* like an array. The column is as follows:
*
* 0. ID (reservations.ID)
* 1. RoomNum
* 2. GuestID
* 3. TransactionID
* 4. IsNoShow
* 5. Type
* 6. Status
* 7. CreationDate
* 8. StartDate
* 9. EndDate
* 10. CheckIn
* 11. CheckOut
* 12. DateChanged
* 13. ID (rooms.ID)
* 14. Rate
* 15. Owed
* 16. Penalty
* 17. Multiplier
* 18. RefundAmount
* 19. AmountPaid
* 20. PayBy
* 21. LastPaid
* 22. PaidOn
* 23. ID (guests.ID)
* 24. Fname
* 25. Lname
* 26. Email
* 27. CreditCard
* 28. Expiration
* 29. CCV
*
*/
Reservation? r;
Transaction? t;
Guest g;
int? RoomNumber = null;
DateTime? CheckIn = null, CheckOut = null, DateChanged = null, LastPaid = null, PaidOn = null;
if (reader.HasRows && !reader.IsDBNull(0))
{
if (reader[21].GetType() != typeof(DBNull))
{
LastPaid = reader.GetDateTime(21);
}
if (reader[22].GetType() != typeof(DBNull))
{
PaidOn = reader.GetDateTime(22);
}
t = new(reader.GetInt32(13), reader.GetDouble(14), reader.GetDouble(15), reader.GetDouble(17), reader.GetDateTime(20), // Creates a new transaction implicitly
LastPaid: LastPaid, PaidOn: PaidOn, RefundAmount: reader.GetDouble(18), Penalty: reader.GetDouble(16), AmountPaid: reader.GetDouble(19));
g = new(reader.GetInt32(23), reader.GetString(24), reader.GetString(25), reader.GetString(26), reader.GetString(27), reader.GetString(28), reader.GetString(29)); // Creates a new guest implicitly
if (reader[1].GetType() != typeof(DBNull))
{
RoomNumber = reader.GetInt32(1);
}
if (reader[10].GetType() != typeof(DBNull))
{
CheckIn = reader.GetDateTime(10);
}
if (reader[11].GetType() != typeof(DBNull))
{
CheckOut = reader.GetDateTime(11);
}
if (reader[12].GetType() != typeof(DBNull))
{
DateChanged = reader.GetDateTime(12);
}
r = new(reader.GetInt32(0), g, t, (ReservationType)reader.GetInt32(5), (ReservationStatus)reader.GetInt32(6), // Creates a new reservation implicitly
reader.GetDateTime(7), reader.GetDateTime(8), reader.GetDateTime(9), RoomNum: RoomNumber, IsNoShow: reader.GetBoolean(4),
CheckIn: CheckIn, CheckOut: CheckOut, DateChanged: DateChanged);
reservations.Add(r);
}
}
}
return reservations;
}
internal static (double, double, List<(DateTime, double)>) GetIncentiveTransactions()
{
/*
* Creates a list of incentive transactions based on a query that gets reservations, and their associated transactions,
* if they match the Incentive type and are active and changed. The matching dates and rates and amount owed are caluclated
* to produce a new column losses. The losses are then added to a list, averaged, and totalled. These are returned.
*/
double losses;
double totalLosses = 0;
int days = 30;
DateTime dt = DateTime.Now;
List<(DateTime, double)> dailyLosses = new();
using (Database Manager = new()) // Create a new database connection
{
for (int i = 0; i < days; i++)
{
using (SQLiteCommand cmd = Manager.con.CreateCommand()) // Create a new command to execute
{
cmd.CommandText = "SELECT sum(transactions.Rate - (transactions.Rate * transactions.Multiplier)) AS Loss " +
"FROM reservations " +
"INNER JOIN transactions ON reservations.TransactionID = transactions.ID " +
"WHERE (DATE(@Date) BETWEEN StartDate AND EndDate) AND STATUS IN (@Status1,@Status2) AND Type = @Type";
cmd.Parameters.AddWithValue("@Date", dt.AddDays(i).Date.ToString("yyyy-MM-dd"));
cmd.Parameters.AddWithValue("@Status1", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@Status2", (int)ReservationStatus.Changed);
cmd.Parameters.AddWithValue("@Type", (int)ReservationType.Incentive);
using SQLiteDataReader reader = cmd.ExecuteReader(); // Create a new reader to read the SQL data
reader.Read();
if (reader.HasRows && !reader.IsDBNull(0))
{
totalLosses += reader.GetDouble(0);
losses = reader.GetDouble(0);
}
else // No losses found
{
losses = 0;
}
}
dailyLosses.Add((dt.AddDays(i), losses));
}
}
return (totalLosses, totalLosses / 30, dailyLosses);
}
internal static (List<(DateTime, double)>, double, double) GetExpectedIncomeCount()
{
/*
* This query gets the the expected income for the next thirty days. The query looks
* for and sums transactions that cover the specified date range and are active or
* changed in status. The expected income is averaged as well and returned as daily
* values.
*/
double totalIncome = 0;
double income;
int days = 30;
DateTime dt = DateTime.Now;
List<(DateTime, double)> dailyIncomes = new();
using (Database Manager = new()) // Create a new database connection
{
for (int i = 0; i < days; i++)
{
using (SQLiteCommand cmd = Manager.con.CreateCommand()) // Create a new command to execute
{
cmd.CommandText = "SELECT sum(transactions.Rate * Multiplier) FROM reservations " +
"INNER JOIN transactions ON reservations.TransactionID = transactions.ID " +
"WHERE (DATE(@Date) BETWEEN StartDate AND EndDate) AND Status IN (@Status1,@Status2);";
cmd.Parameters.AddWithValue("@Date", dt.AddDays(i).Date.ToString("yyyy-MM-dd"));
cmd.Parameters.AddWithValue("@Status1", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@Status2", (int)ReservationStatus.Changed);
using SQLiteDataReader reader = cmd.ExecuteReader(); // Create a new reader to read the SQL data
reader.Read();
if (reader.HasRows && !reader.IsDBNull(0))
{
totalIncome += reader.GetDouble(0);
income = reader.GetDouble(0);
}
else
{
income = 0;
}
}
dailyIncomes.Add((dt.AddDays(i), income));
}
}
return (dailyIncomes, totalIncome, totalIncome / 30);
}
internal static (double, List<(DateTime, int, int, int, int, int)>) GetExpectedOccupancyCount()
{
/*
* This function gets the expected occupancy for the next thirty days. The query looks for
* active or changed reservations based on the current date between matching reservations
* start and end dates. It also runs the query for all and each reservation respectively.
*/
double thirtyDayOcc = 0;
int days = 30;
DateTime dt = DateTime.Now;
List<(DateTime, int, int, int, int, int)> occData = new();
using (Database Manager = new()) // Create a new database connection
{
for (int i = 0; i < days; i++)
{
int rooms, conventional, prepaid, sixty, incentive;
using (SQLiteTransaction Transaction = Manager.con.BeginTransaction()) // Create a new transaction
{
using (SQLiteCommand cmd = Manager.con.CreateCommand()) // Create a new command to execute
{
cmd.CommandText = "SELECT COUNT(*) " +
"FROM reservations " +
"WHERE (DATE(@Date) BETWEEN StartDate AND EndDate) AND Status in (@Status1,@Status2);";
cmd.Parameters.AddWithValue("@Date", dt.AddDays(i).Date.ToString("yyyy-MM-dd"));
cmd.Parameters.AddWithValue("@Status1", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@Status2", (int)ReservationStatus.Changed);
using SQLiteDataReader reader = cmd.ExecuteReader(); // Create a new reader to read the SQL data
reader.Read();
if (reader.HasRows && !reader.IsDBNull(0))
{
thirtyDayOcc += reader.GetInt32(0);
rooms = reader.GetInt32(0);
}
else
{
rooms = 0;
}
}
using (SQLiteCommand cmd = Manager.con.CreateCommand()) // Create a new command to execute
{
/*
* Get total conventional count
*/
cmd.CommandText = "SELECT COUNT(*) " +
"FROM reservations " +
"WHERE (DATE(@Date) BETWEEN StartDate AND EndDate) AND Status in (@Status1,@Status2) AND Type = @Type;";
cmd.Parameters.AddWithValue("@Date", dt.AddDays(i).Date.ToString("yyyy-MM-dd"));
cmd.Parameters.AddWithValue("@Status1", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@Status2", (int)ReservationStatus.Changed);
cmd.Parameters.AddWithValue("@Type", (int)ReservationType.Conventional);
using SQLiteDataReader reader = cmd.ExecuteReader(); // Create a new reader to read the SQL data
reader.Read();
if (reader.HasRows && !reader.IsDBNull(0))
{
conventional = reader.GetInt32(0);
}
else
{
conventional = 0;
}
}
using (SQLiteCommand cmd = Manager.con.CreateCommand())
{
/*
* Get total prepaid count
*/
cmd.CommandText = "SELECT COUNT(*) " +
"FROM reservations " +
"WHERE (DATE(@Date) BETWEEN StartDate AND EndDate) AND Status in (@Status1,@Status2) AND Type = @Type;";
cmd.Parameters.AddWithValue("@Date", dt.AddDays(i).Date.ToString("yyyy-MM-dd"));
cmd.Parameters.AddWithValue("@Status1", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@Status2", (int)ReservationStatus.Changed);
cmd.Parameters.AddWithValue("@Type", (int)ReservationType.Prepaid);
using SQLiteDataReader reader = cmd.ExecuteReader();
reader.Read();
if (reader.HasRows && !reader.IsDBNull(0))
{
prepaid = reader.GetInt32(0);
}
else
{
prepaid = 0;
}
}
using (SQLiteCommand cmd = Manager.con.CreateCommand())
{
/*
* Get total 60-day-in-advance count
*/
cmd.CommandText = "SELECT COUNT(*) " +
"FROM reservations " +
"WHERE (DATE(@Date) BETWEEN StartDate AND EndDate) AND Status in (@Status1,@Status2) AND Type = @Type;";
cmd.Parameters.AddWithValue("@Date", dt.AddDays(i).Date.ToString("yyyy-MM-dd"));
cmd.Parameters.AddWithValue("@Status1", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@Status2", (int)ReservationStatus.Changed);
cmd.Parameters.AddWithValue("@Type", (int)ReservationType.SixtyDayAdvance);
using SQLiteDataReader reader = cmd.ExecuteReader();
reader.Read();
if (reader.HasRows && !reader.IsDBNull(0))
{
sixty = reader.GetInt32(0);
}
else
{
sixty = 0;
}
}
using (SQLiteCommand cmd = Manager.con.CreateCommand())
{
/*
* Get total incentive count
*/
cmd.CommandText = "SELECT COUNT(*) " +
"FROM reservations " +
"WHERE (DATE(@Date) BETWEEN StartDate AND EndDate) AND Status in (@Status1,@Status2) AND Type = @Type;";
cmd.Parameters.AddWithValue("@Date", dt.AddDays(i).Date.ToString("yyyy-MM-dd"));
cmd.Parameters.AddWithValue("@Status1", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@Status2", (int)ReservationStatus.Changed);
cmd.Parameters.AddWithValue("@Type", (int)ReservationType.Incentive);
using SQLiteDataReader reader = cmd.ExecuteReader();
reader.Read();
if (reader.HasRows && !reader.IsDBNull(0))
{
incentive = reader.GetInt32(0);
}
else
{
incentive = 0;
}
}
Transaction.Commit(); // Commit transaction to database
}
occData.Add((dt.AddDays(i), rooms, conventional, prepaid, sixty, incentive));
}
}
return (thirtyDayOcc / days, occData);
}
internal static (int, bool) AvgOccupancySpan(DateTime Start, DateTime End)
{
/*
* This query gets the average occupancy and also reports if there was a
* max capacity found within those 30 days. The count is averaged and returned
* with the boolean value once all reservation queries are checked to match
* the critiera. The search criteria is any active/ changed date where the
* date specified is between the start and end date of any matching reservation.
*/
int thirtyDayOcc = 0;
bool maxCapacityInRange = false;
int days = (int)(End.Date - Start.Date).TotalDays;
using (Database Manager = new()) // Create a new database connection
{
for (int i = 0; i < days; i++)
{
using SQLiteCommand cmd = Manager.con.CreateCommand(); // Create a new command
cmd.CommandText = $@"SELECT COUNT(*)
FROM reservations
WHERE (DATE(@Date) BETWEEN StartDate AND EndDate) AND Status in (@Status1,@Status2);";
cmd.Parameters.AddWithValue("@Date", Start.AddDays(i).Date.ToString("yyyy-MM-dd"));
cmd.Parameters.AddWithValue("@Status1", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@Status2", (int)ReservationStatus.Changed);
using SQLiteDataReader reader = cmd.ExecuteReader(); // Create a new SQL data reader
reader.Read();
if (reader.HasRows && !reader.IsDBNull(0))
{
thirtyDayOcc += reader.GetInt32(0);
if (reader.GetInt32(0) == 45)
{
maxCapacityInRange = true;
}
}
}
}
return (thirtyDayOcc / days, maxCapacityInRange);
}
internal static Guest? GetGuestByEmail(string Email)
{
/*
* This function searches the database for a guest based off
* the specified email. If a match is found the guest model is created and returned.
* If no guest details are found, a null object is returned.
*/
Guest? g = null;
using (Database Manager = new()) // Creates a new database connection
{
using SQLiteCommand cmd = Manager.con.CreateCommand(); // Creates a new database command
cmd.CommandText = $"SELECT * FROM guests WHERE Email = @Email";
cmd.Parameters.AddWithValue("@Email", Email);
using SQLiteDataReader reader = cmd.ExecuteReader(); // Creates a new SQL data reader
reader.Read();
if (reader.HasRows)
{
string? CreditCard = null, Expiration = null, CCV = null;
if (reader[4].GetType() != typeof(DBNull))
{
CreditCard = reader[4].ToString();
}
if (reader[5].GetType() != typeof(DBNull))
{
Expiration = reader[5].ToString();
}
if (reader[6].GetType() != typeof(DBNull))
{
CCV = reader[6].ToString();
}
g = new(reader.GetInt32(0), reader.GetString(1), reader.GetString(2), reader.GetString(3), CreditCard, Expiration, CCV); // Create a guest model
}
}
return g;
}
internal static Reservation? GetResByGuest(Guest g)
{
/*
* This query gets a reservation by taking an existing guest as the "where" comparison.
* Since the guest model is already passed into this query, there is no need to join the
* guests table. Instead only the transaction and reservation details need to be populated
* and then the guest object is passed into the creation of a reservation object.
*/
Reservation? r = null;
Transaction? t;
using (Database Manager = new()) // Opens a database connection
{
using SQLiteCommand cmd = Manager.con.CreateCommand(); // Creates a new command
int? RoomNumber = null;
DateTime? CheckIn = null, CheckOut = null, DateChanged = null, LastPaid = null, PaidOn = null;
cmd.CommandText = @"SELECT * FROM reservations
INNER JOIN transactions ON reservations.TransactionID = transactions.ID
WHERE GuestID = @GuestID AND Status IN (@Status1,@Status2);";
cmd.Parameters.AddWithValue("@GuestID", g.Id);
cmd.Parameters.AddWithValue("@Status1", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@Status2", (int)ReservationStatus.Changed);
using SQLiteDataReader reader = cmd.ExecuteReader(); // Creates a new SQL data reader
reader.Read();
if (reader.HasRows)
{
if (reader[21].GetType() != typeof(DBNull))
{
LastPaid = reader.GetDateTime(21);
}
if (reader[22].GetType() != typeof(DBNull))
{
PaidOn = reader.GetDateTime(22);
}
t = new(reader.GetInt32(13), reader.GetDouble(14), reader.GetDouble(15), reader.GetDouble(17), reader.GetDateTime(20), // Creates a new transaction model
LastPaid: LastPaid, PaidOn: PaidOn, RefundAmount: reader.GetDouble(18), Penalty: reader.GetDouble(16), AmountPaid: reader.GetDouble(19));
if (reader[1].GetType() != typeof(DBNull))
{
RoomNumber = reader.GetInt32(1);
}
if (reader[10].GetType() != typeof(DBNull))
{
CheckIn = reader.GetDateTime(10);
}
if (reader[11].GetType() != typeof(DBNull))
{
CheckOut = reader.GetDateTime(11);
}
if (reader[12].GetType() != typeof(DBNull))
{
DateChanged = reader.GetDateTime(12);
}
r = new(reader.GetInt32(0), g, t, (ReservationType)reader.GetInt32(5), (ReservationStatus)reader.GetInt32(6), // Creates a new reservation model
reader.GetDateTime(7), reader.GetDateTime(8), reader.GetDateTime(9), RoomNum: RoomNumber, IsNoShow: reader.GetBoolean(4),
CheckIn: CheckIn, CheckOut: CheckOut, DateChanged: DateChanged);
}
}
return r;
}
internal static TimeRefs? CanBeCheckedIn(string Email)
{
/*
* This query checks to see if a guest can be checked in. Guest are only
* permitted to check in on the day that their reservation is due to start.
* If they check in to early, the appropriate TimeRef enum is returned to.
*/
TimeRefs? status = null;
using (Database Manager = new()) // Opens a database connection
{
using SQLiteCommand cmd = Manager.con.CreateCommand(); // Creates a new command
cmd.CommandText = "SELECT * FROM reservations " +
"INNER JOIN guests ON reservations.GuestID = guests.ID " +
"WHERE Email = @Email AND Status IN (@Status1,@Status2)";
cmd.Parameters.AddWithValue("@Email", Email);
cmd.Parameters.AddWithValue("@Status1", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@Status2", (int)ReservationStatus.Changed);
using SQLiteDataReader reader = cmd.ExecuteReader(); // Creates a new SQL data reader
reader.Read();
if (reader.HasRows)
{
DateTime dt = reader.GetDateTime(8);
if (dt.Date == DateTime.Now.Date)
{
status = TimeRefs.OnTime;
}
else if (dt.Date > DateTime.Now.Date)
{
status = TimeRefs.Late;
}
else if (dt.Date < DateTime.Now.Date)
{
status = TimeRefs.Early;
}
}
else
{
status = null;
}
}
return status;
}
internal static double? GetBaseRate()
{
/*
* This function is used to get the current base rate that is configured
* to be the default.
*/
double? rate;
using (Database Manager = new()) // Opens a database connection
{
using SQLiteCommand cmd = Manager.con.CreateCommand(); // Creates a new command
string query = "SELECT Rate FROM rates WHERE DefaultRate = 1;";
cmd.CommandText = query;
using SQLiteDataReader reader = cmd.ExecuteReader(); // Creates a new SQL data reader
reader.Read();
if (reader.HasRows)
{
rate = reader.GetDouble(0);
}
else
{
rate = null;
}
}
return rate;
}
internal static bool GetBaseRateByDate(DateTime dt)
{
/*
* Gets the base rate by a specific date. This is typically used to check
* if there is a conflicting rate for a given day and return if a rate has
* been configured for that date.
*/
bool configured;
using (Database Manager = new()) // Opens a database connection
{
using SQLiteCommand cmd = Manager.con.CreateCommand(); // Creates a new command
string query = "SELECT Rate FROM rates WHERE DateSet = @Date;";
cmd.CommandText = query;
cmd.Parameters.AddWithValue("@Date", dt.ToString("yyyy-MM-dd"));
using SQLiteDataReader reader = cmd.ExecuteReader(); // Creates a new SQL data reader
reader.Read();
if (reader.HasRows)
{
configured = true;
}
else
{
configured = false;
}
}
return configured;
}
internal static void SetBaseRate(double Rate, DateTime DateSet, bool? DefaultRate = null)
{
/*
* This function is used to create a new base rate in the database and have the option to make it
* the default base rate.
*/
using Database Manager = new(); // Create a new database connection
using SQLiteCommand cmd = Manager.con.CreateCommand(); // Create a new command
string query = $"INSERT INTO rates (Rate, DateSet, DefaultRate) VALUES (@Rate, @DateSet, @DefaultRate);";
cmd.CommandText = query;
cmd.Parameters.AddWithValue("@Rate", Rate);
cmd.Parameters.AddWithValue("@DateSet", DateSet.ToString("yyyy-MM-dd"));
if (DefaultRate != null)
{
if (DefaultRate.Value == true)
{
cmd.Parameters.AddWithValue("@DefaultRate", Convert.ToInt32(DefaultRate));
}
else
{
cmd.Parameters.AddWithValue("@DefaultRate", null);
}
}
else
{
cmd.Parameters.AddWithValue("@DefaultRate", null);
}
cmd.ExecuteNonQuery();
}
internal static void UpdateBaseRate(double Rate, DateTime DateSet, bool? DefaultRate = null)
{
/*
* This command is used to update the base rate for an existing base rate.
* It will replace the value of any rate, including the default rate if specified.
*/
using Database Manager = new(); // Create a new database connection
using SQLiteCommand cmd = Manager.con.CreateCommand(); // Create a new command
if (DefaultRate != null)
{
if (DefaultRate.Value == true)
{
cmd.CommandText = $"UPDATE rates SET rate = @Rate, defaultrate = @DefaultRate WHERE DateSet = @Date;";
cmd.Parameters.AddWithValue("@DefaultRate", Convert.ToInt32(DefaultRate)); // Replaces existing rate
}
else
{
cmd.CommandText = $"UPDATE rates SET rate = @Rate WHERE DateSet = @Date;";
}
}
else
{
cmd.CommandText = $"UPDATE rates SET rate = @Rate WHERE DateSet = @Date;";
}
cmd.Parameters.AddWithValue("@Rate", Rate);
cmd.Parameters.AddWithValue("@Date", DateSet.ToString("yyyy-MM-dd"));
cmd.ExecuteNonQuery();
}
internal static bool CheckBaseRate()
{
/*
* This function is used to check and update if there is a new base rate.
* It will check to see if there is a base rate set for the current day
* and if that is the case it will set that as the new DefaultRate to use, 1,
* while setting the other one to 0.
*/
int? OldId = null;
bool Success = true;
using (Database Manager = new()) // Open a new database connection
{
using (SQLiteCommand cmd = Manager.con.CreateCommand()) // Create a new command
{
/*
* This query checks for the existing default base rate, if it does not find a rate
* and returns null, then the function will report a boolean value of false.
*/
string query = "SELECT Id FROM rates WHERE DefaultRate = 1;";
cmd.CommandText = query;
using SQLiteDataReader reader = cmd.ExecuteReader(); // Create a new SQL data reader
reader.Read();
if (reader.HasRows)
{
OldId = reader.GetInt32(0);
}
}
int? Id;
if (OldId != null)
{
using (SQLiteCommand cmd = Manager.con.CreateCommand()) // Create a new command
{
/*
* This query selects a base rate configured to the current date
* if it is set. If there is an Id, it will be used in the
* next query for swapping. No swap occurs if it does not exist.
*/
string query = "SELECT Id FROM rates WHERE DateSet = @Date;";
cmd.CommandText = query;
cmd.Parameters.AddWithValue("@Date", DateTime.Now.Date.ToString("yyyy-MM-dd"));
using SQLiteDataReader reader = cmd.ExecuteReader(); // Create a new SQL data reader
reader.Read();
if (reader.HasRows)
{
Id = reader.GetInt32(0);
}
else
{
Id = null;
}
}
if (Id != null)
{
/*
* This query swaps the default indicator of the old base rate with the new base
* rate.
*/
using SQLiteCommand cmd = Manager.con.CreateCommand(); // Create a new command
cmd.CommandText = @"UPDATE rates SET DefaultRate = NULL WHERE Id = @OldID;
UPDATE rates SET DefaultRate = 1 WHERE Id = @ID;";
cmd.Parameters.AddWithValue("@OldID", OldId);
cmd.Parameters.AddWithValue("@ID", Id);
cmd.ExecuteNonQuery();
}
}
else
{
Success = false;
}
}
return Success;
}
internal static int? CheckInGuest(string Email, DateTime CheckIn)
{
/*
* This query is used to check in a guest and is a multi-part query
* with several updates to the database. Here the database tables
* reservation and room will be updated based on whichever
* room is available, not occupied, and then assigned to the reservation.
* Once this is complete, the updated information is saved to the database
* and the room number is returned.
*/
int? RoomID = null;
using (Database Manager = new()) // Opens a new database connection
{
using SQLiteTransaction Transaction = Manager.con.BeginTransaction(); // Begin a new SQL transaction
using (SQLiteCommand cmd = Manager.con.CreateCommand()) // Creates a new command
{
/*
* This query looks at the rooms table for the first instance of an unoccupied
* room. This room is then set as the reservations associated room.
*/
cmd.CommandText = "UPDATE reservations SET RoomNum = (SELECT ID FROM rooms WHERE Occupied = 0 LIMIT 1), CheckIn = @Date " +
"WHERE GuestID = (SELECT ID FROM guests WHERE Email = @Email) AND RoomNum IS NULL AND Status in (@SActive,@SChanged);";
cmd.Parameters.AddWithValue("@Email", Email);
cmd.Parameters.AddWithValue("@SActive", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@SChanged", (int)ReservationStatus.Changed);
cmd.Parameters.AddWithValue("@Date", CheckIn.ToString("yyyy-MM-dd"));
cmd.ExecuteNonQuery();
}
using (SQLiteCommand cmd = Manager.con.CreateCommand()) // Creates a new command
{
/*
* This query sets the room that is assigned to the reservation as
* occupied as a guest has been assigned it.
*/
cmd.CommandText = "UPDATE rooms SET Occupied = 1 " +
"WHERE ID = (SELECT RoomNum FROM reservations WHERE GuestID = (SELECT ID FROM guests WHERE Email = @Email AND Status in (@SActive,@SChanged)));";
cmd.Parameters.AddWithValue("@Email", Email);
cmd.Parameters.AddWithValue("@SActive", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@SChanged", (int)ReservationStatus.Changed);
cmd.ExecuteNonQuery();
}
using (SQLiteCommand cmd = Manager.con.CreateCommand()) // Creates a new command
{
/*
* This query looks for the room number that was assigned as a result of the queries above.
* This room number is then stored so it can be returned.
*/
cmd.CommandText = "SELECT RoomNum FROM reservations WHERE GuestID = (SELECT ID FROM guests WHERE Email = @Email AND Status in (@SActive,@SChanged))";
cmd.Parameters.AddWithValue("@Email", Email);
cmd.Parameters.AddWithValue("@SActive", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@SChanged", (int)ReservationStatus.Changed);
using SQLiteDataReader reader = cmd.ExecuteReader(); // Creates a new SQL reader
reader.Read();
if (reader.HasRows)
{
RoomID = reader.GetInt32(0);
}
}
Transaction.Commit(); // Commits the transaction
}
return RoomID;
}
internal static bool GuestCurrentlyCheckedIn(string Email)
{
/*
* Checks if a guest is currently checked in. If there is a check-in date
* on their reservation, that means thay have been checked in. A boolean
* value is returned whether or not a matching reservation is found.
*/
bool EntryFound;
using (Database Manager = new()) // Creates a new database connection
{
using SQLiteCommand cmd = Manager.con.CreateCommand(); // Creates a new command
cmd.CommandText = "SELECT * FROM reservations " +
"WHERE GuestID = (SELECT ID FROM guests WHERE Email = @Email AND Status in (@SActive,@SChanged)) AND CheckIn IS NOT NULL";
cmd.Parameters.AddWithValue("@Email", Email);
cmd.Parameters.AddWithValue("@SActive", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@SChanged", (int)ReservationStatus.Changed);
using SQLiteDataReader reader = cmd.ExecuteReader(); // Creates a new SQL data reader
reader.Read();
if (reader.HasRows)
{
EntryFound = true;
}
else
{
EntryFound = false;
}
}
return EntryFound;
}
internal static void CheckOutGuest(string Email, DateTime CheckOut)
{
/*
* This function checks a guest out given that they have already checked in
* and have an active reservation. If this criteria is not met, a reservation
* will not be checked out. If a reservation does match this criteria, the reservation
* check-out date is set and the status of the reservation is changed to Ended.
*/
using Database Manager = new(); // Creates a new database connection
using SQLiteTransaction Transaction = Manager.con.BeginTransaction(); // Creates a new SQL data reader
using (SQLiteCommand cmd = Manager.con.CreateCommand()) // Creates a new command
{
/*
* This query looks for the room that is checked in and marks them as unoccupied
* based on the corresponding room to reservation relation.
*/
cmd.CommandText = "UPDATE rooms SET Occupied = 0 " +
"WHERE ID = (SELECT RoomNum FROM reservations WHERE GuestID = (SELECT ID FROM guests WHERE Email = @Email) AND Status in (@SActive,@SChanged) AND CheckIn IS NOT NULL);";
cmd.Parameters.AddWithValue("@Email", Email);
cmd.Parameters.AddWithValue("@SActive", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@SChanged", (int)ReservationStatus.Changed);
cmd.ExecuteNonQuery();
}
using (SQLiteCommand cmd = Manager.con.CreateCommand()) // Creates a new command
{
/*
* This query updates the reservation status as Ended adn the checkout date.
*/
cmd.CommandText = "UPDATE reservations SET CheckOut = @Date, Status = @Status " +
"WHERE GuestID = (SELECT ID FROM guests WHERE Email = @Email) AND RoomNum IS NOT NULL AND Status in (@SActive,@SChanged) AND CheckIn IS NOT NULL;";
cmd.Parameters.AddWithValue("@Email", Email);
cmd.Parameters.AddWithValue("@Status", (int)ReservationStatus.Ended);
cmd.Parameters.AddWithValue("@SActive", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@SChanged", (int)ReservationStatus.Changed);
cmd.Parameters.AddWithValue("@Date", CheckOut.ToString("yyyy-MM-dd"));
cmd.ExecuteNonQuery();
}
Transaction.Commit();
return;
}
internal static List<Reservation> GetActiveSixtyDayRes()
{
/*
* This query is used to build a list of active 60-day-in-advance reservations
* and return them all as a list.
*/
List<Reservation> list = new();
using (Database Manager = new()) // Create a new database connection
{
using SQLiteCommand cmd = Manager.con.CreateCommand(); // Create a new command
/*
* This query will find any reservation with the 60-day type that is Active or Changed
* and return them all in a table
*/
cmd.CommandText = "SELECT * FROM reservations " +
"INNER JOIN transactions ON reservations.TransactionID = transactions.ID " +
"INNER JOIN guests ON reservations.GuestID = guests.ID " +
"WHERE Type = @Type AND Status IN (@Status1,@Status2);";
cmd.Parameters.AddWithValue("@Type", (int)ReservationType.SixtyDayAdvance);
cmd.Parameters.AddWithValue("@Status1", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@Status2", (int)ReservationStatus.Changed);
using SQLiteDataReader reader = cmd.ExecuteReader(); // Create a new SQL data reader
while (reader.Read())
{
Reservation? r;
Transaction? t;
Guest g;
int? RoomNumber = null;
DateTime? CheckIn = null, CheckOut = null, DateChanged = null, LastPaid = null, PaidOn = null;
if (reader.HasRows)
{
/*
* Since we cannot get by string keys, each column is represented by a numerical value
* like an array. The column is as follows:
*
* 0. ID (reservations.ID)
* 1. RoomNum
* 2. GuestID
* 3. TransactionID
* 4. IsNoShow
* 5. Type
* 6. Status
* 7. CreationDate
* 8. StartDate
* 9. EndDate
* 10. CheckIn
* 11. CheckOut
* 12. DateChanged
* 13. ID (rooms.ID)
* 14. Rate
* 15. Owed
* 16. Penalty
* 17. Multiplier
* 18. RefundAmount
* 19. AmountPaid
* 20. PayBy
* 21. LastPaid
* 22. PaidOn
* 23. ID (guests.ID)
* 24. Fname
* 25. Lname
* 26. Email
* 27. CreditCard
* 28. Expiration
* 29. CCV
*
*/
if (reader[21].GetType() != typeof(DBNull))
{
LastPaid = reader.GetDateTime(21);
}
if (reader[22].GetType() != typeof(DBNull))
{
PaidOn = reader.GetDateTime(22);
}
t = new(reader.GetInt32(13), reader.GetDouble(14), reader.GetDouble(15), reader.GetDouble(17), reader.GetDateTime(20), // Creates a new transaction model
LastPaid: LastPaid, PaidOn: PaidOn, RefundAmount: reader.GetDouble(18), Penalty: reader.GetDouble(16), AmountPaid: reader.GetDouble(19));
g = new(reader.GetInt32(23), reader.GetString(24), reader.GetString(25), reader.GetString(26), reader.GetString(27), reader.GetString(28), reader.GetString(29)); // Creates a new guest model
if (reader[1].GetType() != typeof(DBNull))
{
RoomNumber = reader.GetInt32(1);
}
if (reader[10].GetType() != typeof(DBNull))
{
CheckIn = reader.GetDateTime(10);
}
if (reader[11].GetType() != typeof(DBNull))
{
CheckOut = reader.GetDateTime(11);
}
if (reader[12].GetType() != typeof(DBNull))
{
DateChanged = reader.GetDateTime(12);
}
r = new(reader.GetInt32(0), g, t, (ReservationType)reader.GetInt32(5), (ReservationStatus)reader.GetInt32(6),
reader.GetDateTime(7), reader.GetDateTime(8), reader.GetDateTime(9), RoomNum: RoomNumber, IsNoShow: reader.GetBoolean(4),
CheckIn: CheckIn, CheckOut: CheckOut, DateChanged: DateChanged);
list.Add(r);
}
}
}
return list;
}
internal static List<Reservation> GetPastDueReservations()
{
/*
* This function gets any reservation that is past due.
* Past due is considered to be any reservation where the start date is
* older than the current date, the reservation is active or changed, and
* has not been checked in. This list is then returned.
*/
List<Reservation> list = new();
using (Database Manager = new()) // Create a new database connection
{
using SQLiteTransaction Transaction = Manager.con.BeginTransaction(); // Create a new SQL transaction
using (SQLiteCommand cmd = Manager.con.CreateCommand()) // Create a new command
{
/*
* This query selects non-checked in active and changed reeservations where
* the start date is older than the current day. These are considered no-shows.
*/
cmd.CommandText = "SELECT * FROM reservations " +
"INNER JOIN transactions ON reservations.TransactionID = transactions.ID " +
"INNER JOIN guests ON reservations.GuestID = guests.ID " +
"WHERE DATE(@Date) > StartDate AND Status IN (@Status1,@Status2) AND CheckIn IS NULL;";
cmd.Parameters.AddWithValue("@Date", DateTime.Now.Date.ToString("yyyy-MM-dd"));
cmd.Parameters.AddWithValue("@Status1", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@Status2", (int)ReservationStatus.Changed);
using SQLiteDataReader reader = cmd.ExecuteReader(); // Create a new SQL data reader
while (reader.Read())
{
Reservation? r;
Transaction? t;
Guest g;
int? RoomNumber = null;
DateTime? CheckIn = null, CheckOut = null, DateChanged = null, LastPaid = null, PaidOn = null;
if (reader.HasRows)
{
/*
* Since we cannot get by string keys, each column is represented by a numerical value
* like an array. The column is as follows:
*
* 0. ID (reservations.ID)
* 1. RoomNum
* 2. GuestID
* 3. TransactionID
* 4. IsNoShow
* 5. Type
* 6. Status
* 7. CreationDate
* 8. StartDate
* 9. EndDate
* 10. CheckIn
* 11. CheckOut
* 12. DateChanged
* 13. ID (rooms.ID)
* 14. Rate
* 15. Owed
* 16. Penalty
* 17. Multiplier
* 18. RefundAmount
* 19. AmountPaid
* 20. PayBy
* 21. LastPaid
* 22. PaidOn
* 23. ID (guests.ID)
* 24. Fname
* 25. Lname
* 26. Email
* 27. CreditCard
* 28. Expiration
* 29. CCV
*
*/
if (reader[21].GetType() != typeof(DBNull))
{
LastPaid = reader.GetDateTime(21);
}
if (reader[22].GetType() != typeof(DBNull))
{
PaidOn = reader.GetDateTime(22);
}
t = new(reader.GetInt32(13), reader.GetDouble(14), reader.GetDouble(15), reader.GetDouble(17), reader.GetDateTime(20), // Create a new transaction model
LastPaid: LastPaid, PaidOn: PaidOn, RefundAmount: reader.GetDouble(18), Penalty: reader.GetDouble(16), AmountPaid: reader.GetDouble(19));
g = new(reader.GetInt32(23), reader.GetString(24), reader.GetString(25), reader.GetString(26), reader.GetString(27), reader.GetString(28), reader.GetString(29)); // Create a new guest model
if (reader[1].GetType() != typeof(DBNull))
{
RoomNumber = reader.GetInt32(1);
}
if (reader[10].GetType() != typeof(DBNull))
{
CheckIn = reader.GetDateTime(10);
}
if (reader[11].GetType() != typeof(DBNull))
{
CheckOut = reader.GetDateTime(11);
}
if (reader[12].GetType() != typeof(DBNull))
{
DateChanged = reader.GetDateTime(12);
}
r = new(reader.GetInt32(0), g, t, (ReservationType)reader.GetInt32(5), (ReservationStatus)reader.GetInt32(6), // Create a new reservation model
reader.GetDateTime(7), reader.GetDateTime(8), reader.GetDateTime(9), RoomNum: RoomNumber, IsNoShow: reader.GetBoolean(4),
CheckIn: CheckIn, CheckOut: CheckOut, DateChanged: DateChanged);
list.Add(r);
}
}
}
using (SQLiteCommand cmd = Manager.con.CreateCommand())
{
/*
* This query updates reservations where the same criteria above is matched and then
* no-show is set. At some point the order of these queries should be swapped as the first
* can be simplified if we update the table first.
*/
cmd.CommandText = "UPDATE reservations SET IsNoShow = 1, DateChanged = @DateChanged " +
"WHERE DATE (@Date) > StartDate AND Status IN (@Status1,@Status2) AND CheckIn IS NULL";
cmd.Parameters.AddWithValue("@Date", DateTime.Now.Date.ToString("yyyy-MM-dd"));
cmd.Parameters.AddWithValue("@DateChanged", DateTime.Now.Date.ToString("yyyy-MM-dd"));
cmd.Parameters.AddWithValue("@Status1", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@Status2", (int)ReservationStatus.Changed);
cmd.ExecuteNonQuery();
}
Transaction.Commit(); // Commits the transaction
}
return list;
}
}
internal enum TimeRefs // Numerical values represented as words
{
OnTime,
Early,
Late
}
}