Adds documentation to the main program.cs

This commit is contained in:
雲華
2022-04-17 00:44:54 -04:00
parent 972a968994
commit 28890a2b6a
2 changed files with 396 additions and 97 deletions

View File

@@ -37,7 +37,8 @@ namespace Ophelias.Managers
cmd.CommandText = "SELECT RoomNum, Lname, Fname, EndDate FROM reservations " + cmd.CommandText = "SELECT RoomNum, Lname, Fname, EndDate FROM reservations " +
"INNER JOIN guests ON reservations.GuestID = guests.ID " + "INNER JOIN guests ON reservations.GuestID = guests.ID " +
"INNER JOIN rooms ON reservations.RoomNum = rooms.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;"; "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("@Date", DateTime.Now.Date.ToString("yyyy-MM-dd"));
cmd.Parameters.AddWithValue("@Status1", (int)ReservationStatus.Active); cmd.Parameters.AddWithValue("@Status1", (int)ReservationStatus.Active);
cmd.Parameters.AddWithValue("@Status2", (int)ReservationStatus.Changed); cmd.Parameters.AddWithValue("@Status2", (int)ReservationStatus.Changed);
@@ -54,7 +55,7 @@ namespace Ophelias.Managers
cmd.CommandText = "SELECT RoomNum FROM reservations " + cmd.CommandText = "SELECT RoomNum FROM reservations " +
"INNER JOIN guests ON reservations.GuestID = guests.ID " + "INNER JOIN guests ON reservations.GuestID = guests.ID " +
"INNER JOIN rooms ON reservations.RoomNum = rooms.ID " + "INNER JOIN rooms ON reservations.RoomNum = rooms.ID " +
"WHERE DATE (@Date) = EndDate AND Status IN (@Status1);"; "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("@Date", DateTime.Now.AddDays(-1).Date.ToString("yyyy-MM-dd"));
cmd.Parameters.AddWithValue("@Status1", (int)ReservationStatus.Ended); cmd.Parameters.AddWithValue("@Status1", (int)ReservationStatus.Ended);
using (SQLiteDataReader reader = cmd.ExecuteReader()) using (SQLiteDataReader reader = cmd.ExecuteReader())

View File

@@ -8,6 +8,12 @@ internal class Program
{ {
private static string GetGuestEmail() private static string GetGuestEmail()
{ {
/*
* This is a function that previously resided
* within the GuestMode(), however this functionality
* has been moved out as the AdminMode() relies on it
* since this essentially is a email validation prompt.
*/
Console.Write("Specify email: "); Console.Write("Specify email: ");
string Email = ""; string Email = "";
while (!Validation.ValidateEmail(Email)) while (!Validation.ValidateEmail(Email))
@@ -23,10 +29,21 @@ internal class Program
private static void GuestMode() private static void GuestMode()
{ {
Reservation? activeReservation = null; /*
Guest? activeGuest = null; * Guest mode is meant for guests to create an account and make a reservation.
* Specifically this mode allows for guests to create an account containing their
* personal and payment information, create a reservation, manage that reservation, and/ or
* pay for that reservation.
*/
Reservation? activeReservation = null; // Holds the current reservation if one is loaded
Guest? activeGuest = null; // Holds the active guest if one logs in
void help() void help()
{ {
/*
* Used to inform users on what the commands do. See
* the main while loop in GuestMode() for more details
* on what these mean.
*/
Console.WriteLine( Console.WriteLine(
"Reservation Commands:\n" + "Reservation Commands:\n" +
"\treservation create - Create a new reservation.\n" + "\treservation create - Create a new reservation.\n" +
@@ -41,9 +58,15 @@ internal class Program
); );
return; return;
} }
(string?, string?, string?) GetCreditCardInformation() (string?, string?, string?) GetCreditCardInformation()
{ {
/*
* This function attempts to gather creditcard information.
* Since we need all three pieces, card number, expiration, and CCV
* we provide options to quit for which the information is discarded
* and null values are returned. If valid inputs are input and all
* three pieces are collected, they are returned.
*/
Console.Write("What is your credit card number: "); Console.Write("What is your credit card number: ");
string CreditCard = ""; string CreditCard = "";
while (!Validation.ValidateCreditCard(CreditCard)) while (!Validation.ValidateCreditCard(CreditCard))
@@ -93,6 +116,11 @@ internal class Program
} }
(string, string) GetGuestName() (string, string) GetGuestName()
{ {
/*
* This function is a series of while loops that will attempt
* to collect a users first and last name, these are then returned
* to the call location.
*/
Console.Write("What is your first name: "); Console.Write("What is your first name: ");
string FirstName = ""; string FirstName = "";
while (FirstName.Length == 0) while (FirstName.Length == 0)
@@ -117,10 +145,21 @@ internal class Program
} }
void GuestLogin() void GuestLogin()
{ {
/*
* This function will attempt to login using an email specified by
* the guest. We use email because they are designated as unique
* identifiers and no two users can have the same email. For that reason
* we use emails to login rather than collecting multiple pieces of
* information or returning a list of accounts to scroll through.
*/
Console.Write("\nEnter your email address: "); Console.Write("\nEnter your email address: ");
string email = ""; string email = "";
while (!Validation.ValidateEmail(email)) while (!Validation.ValidateEmail(email))
{ {
/*
* This loop attepts to get a valid email. If there is no valid
* formatted email it will keep trying.
*/
email = Console.ReadLine(); email = Console.ReadLine();
if (!Validation.ValidateEmail(email)) if (!Validation.ValidateEmail(email))
{ {
@@ -138,6 +177,11 @@ internal class Program
} }
void CreateNewGuestPrompt() void CreateNewGuestPrompt()
{ {
/*
* This prompt allows guest to create a new account using functionality that
* has been split into other functions. See those functions for details on how
* they work.
*/
(string FirstName, string LastName) = GetGuestName(); (string FirstName, string LastName) = GetGuestName();
string Email = GetGuestEmail(); string Email = GetGuestEmail();
Console.Write("Would you like to enter your credit card details? (Y/n): "); Console.Write("Would you like to enter your credit card details? (Y/n): ");
@@ -167,6 +211,12 @@ internal class Program
} }
void UpdateGuestInformation() void UpdateGuestInformation()
{ {
/*
* This function allows a guest, if logged in, to update any piece of their
* personal information. This includes name, email, and creditcard information.
* For more information on how this gets set on the backend, see UpdateGuest()
* in the Guest model.
*/
if (activeGuest == null) if (activeGuest == null)
{ {
Console.WriteLine("No guest is currently logged in, please login."); Console.WriteLine("No guest is currently logged in, please login.");
@@ -177,6 +227,11 @@ internal class Program
void SavePrompt() void SavePrompt()
{ {
/*
* This save prompt is just to inform users of their changes and show them
* what information gets updated. Also calls the UpdateGuest() function to
* update the database.
*/
if (NewFname == null && NewLname == null && NewEmail == null && NewCard == null && NewExpiry == null && NewCCV == null) if (NewFname == null && NewLname == null && NewEmail == null && NewCard == null && NewExpiry == null && NewCCV == null)
{ {
Console.WriteLine("No changes have been made."); Console.WriteLine("No changes have been made.");
@@ -231,12 +286,18 @@ internal class Program
do do
{ {
/*
* This loop traps users until the enter one of the cases which results
* in updating a piece of information, saving their changes, or discarding
* them.
*/
Console.Write("Please select the option you would like to change or enter S to save:\n" + Console.Write("Please select the option you would like to change or enter S to save:\n" +
"1. First Name and Last Name\n" + "1. First Name and Last Name\n" +
"2. Email Address\n" + "2. Email Address\n" +
"3. Credit Card Information\n"); "3. Credit Card Information\n");
switch (Console.ReadLine()) switch (Console.ReadLine())
{ {
case "q": return;
case "Q": return; case "Q": return;
case "1": (NewFname, NewLname) = GetGuestName(); break; case "1": (NewFname, NewLname) = GetGuestName(); break;
case "2": NewEmail = GetGuestEmail(); break; case "2": NewEmail = GetGuestEmail(); break;
@@ -248,6 +309,12 @@ internal class Program
} }
ReservationType SelectReservation() ReservationType SelectReservation()
{ {
/*
* This function was broken out to allow it to be reused in multiple sections.
* It prompts a user for their selection of reservation type and that type
* is then returned. We subtract 1 from the type since we start our input
* options at 1 instead of 0 (Enums start at 0).
*/
string input = ""; string input = "";
Console.Write("What kind of reservation would you like to make?\n" + Console.Write("What kind of reservation would you like to make?\n" +
"1. Conventional\n" + "1. Conventional\n" +
@@ -269,6 +336,12 @@ internal class Program
} }
bool CheckReservationRestrictions(DateTime Date, ReservationType Type) bool CheckReservationRestrictions(DateTime Date, ReservationType Type)
{ {
/*
* This function checks to see if there are reservation restrictions.
* Prepaid reservations must be made 90 days ahead of the start date
* and 60-day 60 days. This function informs the user if their reservation
* does not adhere to these constraints.
*/
if (Type == ReservationType.Prepaid) if (Type == ReservationType.Prepaid)
{ {
if ((int)(Date - DateTime.Now).TotalDays < 90) if ((int)(Date - DateTime.Now).TotalDays < 90)
@@ -384,49 +457,17 @@ internal class Program
return (StartDate, EndDate); return (StartDate, EndDate);
} }
void EditReservationPrompt()
{
string input;
DateTime? NewStartDate = activeReservation.StartDate, NewEndDate = activeReservation.EndDate;
ReservationType NewType = activeReservation.Type;
bool completed = false;
do
{
Console.Write("What information would you like to edit?\n" +
"If not and you wish to cancel, enter Q to exit. If you want to save and complete your changes, enter S.\n" +
"1. Reservation type\n" +
"2. Reservation dates\n" +
"Enter 1 or 2: ");
input = Console.ReadLine();
switch (input)
{
case "Q": Console.WriteLine("Changes have has been deleted."); return;
case "1": NewType = SelectReservation(); break;
case "2": (NewStartDate, NewEndDate) = SelectDate(NewType); break;
case "S":
if (NewStartDate == null || NewEndDate == null)
{
return;
}
while (CheckReservationRestrictions((DateTime)NewStartDate, NewType))
{
(NewStartDate, NewEndDate) = SelectDate(NewType);
if (NewStartDate == null || NewEndDate == null)
{
return;
}
}
completed = true;
(activeReservation.Type, activeReservation.StartDate, activeReservation.EndDate) = (NewType, (DateTime)NewStartDate, (DateTime)NewEndDate);
break;
default: break;
}
} while (!completed);
}
void CreateNewReservation() void CreateNewReservation()
{ {
/*
* Allows users with no existing reservation to make a new reservation.
* If a user is not logged in, they will not be able to register either.
* The reservation will collect all the necessary information depending
* on requirements set by the reservation. Specifically if the reservation
* is anything but 60-day-in-advance, the creditcard is required. If users
* do not want to proceed, the are free to cancel and abort the creation
* of their reservation.
*/
if (activeGuest == null) if (activeGuest == null)
{ {
Console.WriteLine("No guest is currently logged in, please login."); Console.WriteLine("No guest is currently logged in, please login.");
@@ -490,12 +531,12 @@ internal class Program
input = Console.ReadLine(); input = Console.ReadLine();
} }
} }
if (Type == ReservationType.Prepaid) if (Type == ReservationType.Prepaid) // Creates a new reservation and set it as the active. Also pays for the reservation if the reservation type was prepaid.
{ {
activeReservation = new(activeGuest, Type, DateTime.Now.Date, StartDate.Value, EndDate.Value); activeReservation = new(activeGuest, Type, DateTime.Now.Date, StartDate.Value, EndDate.Value);
activeReservation.Transaction.Pay(activeReservation.Transaction.Owed, activeGuest.CreditCard); activeReservation.Transaction.Pay(activeReservation.Transaction.Owed, activeGuest.CreditCard);
} }
else else // Creates a new reservation and set it as the active.
{ {
activeReservation = new(activeGuest, Type, DateTime.Now.Date, StartDate.Value, EndDate.Value); activeReservation = new(activeGuest, Type, DateTime.Now.Date, StartDate.Value, EndDate.Value);
} }
@@ -503,6 +544,16 @@ internal class Program
} }
void UpdateReservation() void UpdateReservation()
{ {
/*
* Update reservation allows guests to change their reservation at the
* cost of having to pay a new amount based on the current base rate
* with a multiplier of 110% or 1.1. If a user opts to not update
* their reservation the changes will be discarded. Furthermore the
* system prevents people from registering when the hotel is at max
* capacity for a certain date. For more details, see the SelectDate()
* function. If a user is not logged in, they will not be able to update
* their reservation.
*/
string input = "NO"; string input = "NO";
if (activeGuest == null) if (activeGuest == null)
{ {
@@ -556,6 +607,13 @@ internal class Program
} }
void CancelReservation() void CancelReservation()
{ {
/*
* This function will provide guests with the option to cancel their reservation
* or abort if they decide they do not want to cancel. If the reservation is cancelled,
* the reservation cancellation function CancelReservation() is called on the reservation
* and the database is updated accordingly. See CancelReservation() for more details.
* If a user is not logged in, they will not be able to cancel either.
*/
if (activeGuest == null) if (activeGuest == null)
{ {
Console.WriteLine("No guest is currently logged in, please login."); Console.WriteLine("No guest is currently logged in, please login.");
@@ -590,6 +648,17 @@ internal class Program
} }
void PayForReservation() void PayForReservation()
{ {
/*
* This function allows for guests to pay for their 60-day-in-advance if they
* meet the 30-45 day before start date window. All other reservations are denied
* the ability to pay since they have specific points at which they are charged.
* If there is no creditcard information, this function will attempt to collect it
* and then update the guests information before paying for the transaction. Depending
* on various factors, the transaction may be completed or invalid. However
* since the current design is to have members pay in full, most of these cases
* should be impossible to trigger. Currently they are implemented for future changes
* or if they do trigger.
*/
if (activeGuest == null) if (activeGuest == null)
{ {
Console.WriteLine("No guest is currently logged in, please login."); Console.WriteLine("No guest is currently logged in, please login.");
@@ -617,6 +686,11 @@ internal class Program
return; return;
} else if (ReservationType.SixtyDayAdvance == activeReservation.Type) } else if (ReservationType.SixtyDayAdvance == activeReservation.Type)
{ {
/*
* Checks to see if the reservation has been paid for are is past the latest possible
* payment date. If it has been payed, the user will be informed, if it is past the
* payment collection date, the reservation is cancelled and user is notified.
*/
if(activeReservation.StartDate.AddDays(-30).Date < DateTime.Now.Date) if(activeReservation.StartDate.AddDays(-30).Date < DateTime.Now.Date)
{ {
if (activeReservation.Transaction.Owed <= activeReservation.Transaction.AmountPaid) if (activeReservation.Transaction.Owed <= activeReservation.Transaction.AmountPaid)
@@ -636,10 +710,18 @@ internal class Program
ccv = activeGuest.CCV; ccv = activeGuest.CCV;
while (true) while (true)
{ {
if (cc == null || exp == null || ccv == null) /*
(cc, exp, ccv) = GetCreditCardInformation(); * This loop traps the user until they either choose to pay or not.
* If the card details they specify are invalid at any point within the latest
* date of the payment, we choose to reject that as it theoretically could cause
* problems. In this hypothetical situation is would not but in the real world it
* might depending on the card vendor. If a user choses to abort payment, the function
* will discard any changes to that guests payment information if changes were made.
* In the case where a customers payment information is already valid, they will pay for
* the reservation in full without any prompts.
*/
if (cc == null || exp == null || ccv == null) if (cc == null || exp == null || ccv == null) // Trigger to get new card information
{ {
Console.Write("Would you like to try again and enter your payment information? (Your reservation will not be canceled)\n" + Console.Write("Would you like to try again and enter your payment information? (Your reservation will not be canceled)\n" +
"YES or NO: "); "YES or NO: ");
@@ -659,8 +741,31 @@ internal class Program
Console.WriteLine("Input must be YES or NO."); Console.WriteLine("Input must be YES or NO.");
} }
} }
(cc, exp, ccv) = GetCreditCardInformation(); // See for more information on how input is collected.
} else if (cc != null && exp != null && ccv != null) } else if (cc != null && exp != null && ccv != null)
{ {
/*
* If the creditcard is not null, this section checks to see if payment can be made.
* If payment can be made the guest information is updated and an attempt to pay is made.
* The payment can result in any of the following:
*
* Successful
* Payment was made and recorded
*
* Failed
* An error occurred and the staff should be notified
*
* Attempt to pay $0 or less
* Self explanatory
*
* Missing card information
* If the card is missing payments cannot be made
*
* Already Paid
* The payment has already been paid at an earlier date
* or due to some other factor, therefore there was no need to charge.
*/
if (ReservationType.SixtyDayAdvance == activeReservation.Type && ((DateTime.Parse(exp).Date < activeReservation.StartDate.AddDays(-30).Date) && (DateTime.Parse(exp).Date < activeReservation.StartDate.AddDays(-45).Date))) if (ReservationType.SixtyDayAdvance == activeReservation.Type && ((DateTime.Parse(exp).Date < activeReservation.StartDate.AddDays(-30).Date) && (DateTime.Parse(exp).Date < activeReservation.StartDate.AddDays(-45).Date)))
{ {
Console.WriteLine("Your card expires too soon. Please enter the correct expiration date if incorrect or a new card."); Console.WriteLine("Your card expires too soon. Please enter the correct expiration date if incorrect or a new card.");
@@ -707,20 +812,57 @@ internal class Program
); );
while (true) while (true)
{ {
/*
* This is the main administrator loop.
* The following are valid operations:
*
* reservation create:
* Creates a new reservation with the information specified by the guest.
* For more information see the CreateNewReservation() function.
*
* reservation update:
* Updates an existing reservation if there is one. If there is no existing
* reservation the function will immediately return. To get more information
* see the UpdateReservation() function.
*
* reservation cancel:
* Cancels a reservation. If the reservation is subject to penalties, the
* guest will be charged. For more infromation, see CancelReservation().
*
* reservation pay:
* Enables 60-day-in-advance reservees to pay for their reservations if
* they are within the valid payment window. Other reservation types will
* be blocked. For more details, see PayForReservation().
*
* account create:
* Enables guests to create a new account. See CreateNewGuestPrompt for
* more details on account creation.
*
* account update:
* Update an existing guests information, such as name, email, and
* creditcard information. For more details on how this is handled,
* see UpdateGuestInformation().
*
* account login:
* Logs into an account using a guests email if they have an account.
* For more details see GuestLogin().
*
* Q and q:
* Returns to the main loop for choosing either the Guest or Admin flow.
*/
string? input = Console.ReadLine(); string? input = Console.ReadLine();
switch (input) switch (input)
{ {
case "help": help(); break; case "help": help(); break; // Gets help text
case "reservation create": CreateNewReservation(); break; case "reservation create": CreateNewReservation(); break; // Allows guests to create a reservation
case "reservation update": UpdateReservation(); break; case "reservation update": UpdateReservation(); break; // Allows guests to update a reservation if they have one
case "reservation cancel": CancelReservation(); break; case "reservation cancel": CancelReservation(); break; // Allows guests to cancel a reservation if they have one
case "reservation pay": PayForReservation(); break; case "reservation pay": PayForReservation(); break; // Allows guests with 60-day reservations to pay for it
case "account create": CreateNewGuestPrompt(); break; case "account create": CreateNewGuestPrompt(); break; // Creates a new guest
case "account update": UpdateGuestInformation(); break; case "account update": UpdateGuestInformation(); break; // Updates a guests personal and/ or payment information
case "account login": GuestLogin(); break; case "account login": GuestLogin(); break; // Logs a guest in
case "q": return; case "q": return; // Quit to mode loop
case "Q": return; case "Q": return; // Quit to mode loop
default: Console.WriteLine("Unknown command, enter help for more inforamtion."); break; default: Console.WriteLine("Unknown command, enter help for more inforamtion."); break;
} }
Console.Write("\nCommand: "); Console.Write("\nCommand: ");
@@ -728,29 +870,55 @@ internal class Program
} }
private static void AdminMode() private static void AdminMode()
{ {
/*
* Admin mode is meant for employees. There is no authetication or security measures
* for this class as the design specification did not include that and for the goals
* of this project, security was not to be a concern. Realistically this would be
* handled differently and securely.
*
* The pupose of this class is to provide employees with the ability to perform
* specific operations such as checking/ checking out a guest, generating
* reports that management needs to understand how the hotel is operating,
* a system to set the hotels rates, and the ability to issue penalties and/ or
* notify outstanding payments. For more details on how each of these components work,
* see the documentation within their functions.
*/
void help() void help()
{ {
/*
* Help text to understand commands.
*/
Console.WriteLine( Console.WriteLine(
"Report Commands:\n" + "Report Commands:\n" +
"\tgenerate management report - Generates a daily management report on expected occupancy, room income, and incentive losses.\n" + "\tgenerate management report - Generates a daily management report on expected occupancy, room income, and incentive losses.\n" +
"\tgenerate operational report - Generates a report of daily arrivals and occupancy.\n" + "\tgenerate operational report - Generates a report of daily arrivals and occupancy.\n" +
"\tgenerate accommodation bills - Generates an accommodation bill that will be handed to guests upon checkout.\n" + "\tgenerate accommodation bills - Generates an accommodation bill that will be handed to guests upon checkout.\n" +
"\treservation cancel\n" + "\nManagement Commands:\n" +
"Management Commands:" + "\tnotify pending payments - Generates and emails 60 day advance reservations that they must pay for their reservation or it will be cancelled.\n" +
"\nnotify pending payments - Generates and emails 60 day advance reservations that they must pay for their reservation or it will be cancelled." + "\tissue penalties - Issues penalties for guests that are no shows.\n" +
"\nissue penalties - Issues penalties for guests that are no shows." +
"\tcheckin guest - Checks in a guest and assigns them a room.\n" + "\tcheckin guest - Checks in a guest and assigns them a room.\n" +
"\tcheckout guest - Checks out a guest and removes their room assignment.\n" + "\tcheckout guest - Checks out a guest and removes their room assignment.\n" +
"\tset rate - Sets a new base rate to begin after a specified date.\n" + "\tset rate - Sets a new base rate to begin after a specified date.\n" +
"Enter Q or q to quit.\n" "\nEnter Q or q to quit.\n"
); );
return; return;
} }
void SetFutureBaseRate() void SetFutureBaseRate()
{ {
/*
* Allows employees to configure a future base rate. See SetRatePrompt() for the
* details as it was broken out into a nested function.
*/
bool SetRatePrompt(DateTime? FixedDate = null) bool SetRatePrompt(DateTime? FixedDate = null)
{ {
/*
* This function promopts an employee with a base rate configuration prompt.
* If this is the first time configuring the base rate, in cases where one is not set,
* the default rate will be set effective immediately, otherwise the base rate prompt
* will require the employee to set the base rate sometime in the future. The accepted inputs
* are checked against the function ValidateMoney() which basically checks for how money is typically
* represented in the United States.
*/
string input; string input;
string amount; string amount;
amount = Console.ReadLine(); amount = Console.ReadLine();
@@ -783,13 +951,13 @@ internal class Program
": "); ": ");
if (Console.ReadLine() == "YES") if (Console.ReadLine() == "YES")
{ {
Hotel.UpdateBaseRate(Convert.ToDouble(amount), FixedDate.Value.Date, DefaultRate: true); Hotel.UpdateBaseRate(Convert.ToDouble(amount), FixedDate.Value.Date, DefaultRate: true); // Replaces the existing base rate with a new value if the date matches. Also marks as default.
return true; return true;
} }
} }
else else
{ {
Hotel.SetBaseRate(Convert.ToDouble(amount), (DateTime)FixedDate, true); Hotel.SetBaseRate(Convert.ToDouble(amount), (DateTime)FixedDate, true); // Sets the base rate as the default.
} }
Console.WriteLine($"A base rate of {amount} has been set and will take effect immediately."); Console.WriteLine($"A base rate of {amount} has been set and will take effect immediately.");
@@ -816,7 +984,7 @@ internal class Program
": "); ": ");
if (Console.ReadLine() == "YES") if (Console.ReadLine() == "YES")
{ {
Hotel.UpdateBaseRate(Convert.ToDouble(amount), StartDate.Date); Hotel.UpdateBaseRate(Convert.ToDouble(amount), StartDate.Date); // Replaces the existing base rate with a new value if the date matches.
return true; return true;
} }
} }
@@ -828,7 +996,7 @@ internal class Program
Console.Write("Please enter a valid date (2021-12-31): "); Console.Write("Please enter a valid date (2021-12-31): ");
} }
Hotel.SetBaseRate(Convert.ToDouble(amount), StartDate); Hotel.SetBaseRate(Convert.ToDouble(amount), StartDate); // Sets the base rate as a future base rate.
Console.WriteLine($"A base rate of {amount} has been set and will take effect on {DateTime.Now.Date.ToString("yyyy-MM-dd")}."); Console.WriteLine($"A base rate of {amount} has been set and will take effect on {DateTime.Now.Date.ToString("yyyy-MM-dd")}.");
} }
return true; return true;
@@ -844,20 +1012,29 @@ internal class Program
if (Hotel.GetBaseRate() == null) if (Hotel.GetBaseRate() == null)
{ {
// This is for the specific case where there is no configured/ default rate.
Console.Write("No base rate has been configured. " + Console.Write("No base rate has been configured. " +
"You must set one for the current date.\n" + "You must set one for the current date.\n" +
"Enter new rate: "); "Enter new rate: ");
while (!SetRatePrompt(DateTime.Now.Date)) { } while (!SetRatePrompt(DateTime.Now.Date)) { } // Continues to loop until a base rate is successfully configured.
} }
else else
{ {
Console.Write("What is the value of the rate you would like to set.\n" + Console.Write("What is the value of the rate you would like to set.\n" +
"Enter new rate: "); "Enter new rate: ");
while (!SetRatePrompt()) { } while (!SetRatePrompt()) { } // Continues to loop until a base rate is successfully configured.
} }
} }
void CheckIn() void CheckIn()
{ {
/*
* Checks in a guest if they have an existing reservation that can be checked in.
* If not the function informs the employee that no reservation exists or no guest
* guest account could be found. This function will also assign the guest their room
* number or cancel their reservation if they attempt to check in after their start date
* as the policy calls for "no-shows" to be charged and therefore are canceled due to a
* no refund policy. Guests also cannot check in ahead of time, only on the day of.
*/
string Email = GetGuestEmail(); string Email = GetGuestEmail();
TimeRefs? status = Hotel.CanBeCheckedIn(Email); TimeRefs? status = Hotel.CanBeCheckedIn(Email);
Guest? g = Hotel.GetGuestByEmail(Email); Guest? g = Hotel.GetGuestByEmail(Email);
@@ -901,6 +1078,12 @@ internal class Program
} }
void CheckOut() void CheckOut()
{ {
/*
* Checks out a guest and charges them if they have an incentive or conventional reservation.
* For more details on how the data is manipulated, see Pay() and CheckOutGuest(). While
* there are null refs warnings here, they should never reach this point
* so we choose not to handle them.
*/
string Email = GetGuestEmail(); string Email = GetGuestEmail();
if (Hotel.GuestCurrentlyCheckedIn(Email)) if (Hotel.GuestCurrentlyCheckedIn(Email))
{ {
@@ -921,6 +1104,12 @@ internal class Program
} }
void NotifyOutstandingPayments() void NotifyOutstandingPayments()
{ {
/*
* This function is used to notify any 60-day-in-advance reservation that they have a payment
* due. If the payment is past the number of days then the reservation is canceled. If the
* reservation is within the 30-45 day window then an email is sent out for a customer to
* pay through the payment system. For more details on how the email works, see the Email class.
*/
List<Reservation> activeSixtyRes = Hotel.GetActiveSixtyDayRes(); List<Reservation> activeSixtyRes = Hotel.GetActiveSixtyDayRes();
foreach (Reservation r in activeSixtyRes) foreach (Reservation r in activeSixtyRes)
{ {
@@ -935,14 +1124,35 @@ internal class Program
e.Send(); e.Send();
} }
} }
if (File.Exists("Emails.txt")) if (File.Exists("Emails.txt") && activeSixtyRes.Count != 0)
{ {
FileInfo f = new("Emails.txt"); FileInfo f = new("Emails.txt");
Console.WriteLine($"Emails have been written and appended to {f.FullName}"); Console.WriteLine($"Emails have been written and appended to {f.FullName}");
} else
{
Console.WriteLine("There are no emails to send.");
} }
} }
void GenerateManagementReports() void GenerateManagementReports()
{ {
/*
* GenerateManagementReports is used to generate the following reports:
*
* - Expected Occupancy
* Reports the expected hotel occupancy and relies on GetExpectedOccupancyCount()
* for the data used in reporting. See CalculateExpectedOccupancy() for more details
* on the output.
*
* - Expected Income
* Reports the expected income for the hotel and relies on GetExpectedIncomeCount()
* for the data used in reporting. See CalculateExpectedIncome() for more details
* on the output.
*
* - Incentive Losses
* Reports the revenue lost as a result of providing incentives and relies on
* GetIncentiveTransactions() for the data used in reporting. See CalculateIncentiveLosses()
* for more details on the output.
*/
var w = Hotel.GetExpectedOccupancyCount(); var w = Hotel.GetExpectedOccupancyCount();
Management.CalculateExpectedOccupancy(w.Item2, w.Item1); Management.CalculateExpectedOccupancy(w.Item2, w.Item1);
if (File.Exists("ExpectedOccupancy.txt")) if (File.Exists("ExpectedOccupancy.txt"))
@@ -967,7 +1177,19 @@ internal class Program
} }
void GenerateAccommodationBills() void GenerateAccommodationBills()
{ {
/*
* This generates a single report called accommodation bills. If there
* are no reservations there will be no accomodation bills to generate.
* The reservations are returned by GetDailyArrivals().
*/
List<Reservation> reservations = Hotel.GetDailyArrivals(); List<Reservation> reservations = Hotel.GetDailyArrivals();
if (reservations.Count == 0)
{
Console.WriteLine($"No accommodation bills to generate.");
return;
}
Accommodation.GenerateAccommodationBills(reservations); Accommodation.GenerateAccommodationBills(reservations);
if (File.Exists("AccommodationBills.txt")) if (File.Exists("AccommodationBills.txt"))
@@ -978,14 +1200,37 @@ internal class Program
} }
void GenerateOperationalReports() void GenerateOperationalReports()
{ {
/*
* This generates two operational reports. The daily arrivals and the daily occupancy.
* The daily arrival report is generated based off list of reservations returned by
* GetDailyArrivals(). This is then passed off to the Operational reporting class
* where it writes out to DailyArrivals.txt. THe same applies to the daily occupancy
* however the GetDailyOccupancy() function is a litte more complex returning two lists,
* one with the occupancy for that day and one with rooms occupied the night before.
* If the file(s) are successfully written, the output is printed to the console for
* staff to find them.
*/
List<Reservation> reservations = Hotel.GetDailyArrivals(); List<Reservation> reservations = Hotel.GetDailyArrivals();
if (reservations.Count == 0)
{
Console.WriteLine($"No daily arrivals to report.");
} else
{
Operational.FetchDailyArriavals(reservations); Operational.FetchDailyArriavals(reservations);
if (File.Exists("DailyArrivals.txt")) if (File.Exists("DailyArrivals.txt"))
{ {
FileInfo f = new("DailyArrivals.txt"); FileInfo f = new("DailyArrivals.txt");
Console.WriteLine($"Daily arrivals have been written and appended to {f.FullName}"); Console.WriteLine($"Daily arrivals have been written and appended to {f.FullName}");
} }
var x = Hotel.GetDailyOccupancy(); }
var x = Hotel.GetDailyOccupancy(); // Using var instead of explicity breaking out the tuple since it's simpler
if (x.Item1.Count == 0)
{
Console.WriteLine($"No daily occupancies to report.");
} else
{
Operational.FetchDailyOccupancy(x.Item1, x.Item2); Operational.FetchDailyOccupancy(x.Item1, x.Item2);
if (File.Exists("DailyOccupancy.txt")) if (File.Exists("DailyOccupancy.txt"))
{ {
@@ -993,8 +1238,15 @@ internal class Program
Console.WriteLine($"Daily occupancy has been written and appended to {f.FullName}"); Console.WriteLine($"Daily occupancy has been written and appended to {f.FullName}");
} }
} }
}
void IssuePenalties() void IssuePenalties()
{ {
/*
* Iterates over a list of reservations returned by GetPastDueReservations(),
* a function of the Hotel class. Since all the reservations returned are known
* to be past due, the cancellation function is called and the reservation is
* canceled and charged if applicable.
*/
List<Reservation> reservations = Hotel.GetPastDueReservations(); List<Reservation> reservations = Hotel.GetPastDueReservations();
foreach (Reservation reservation in reservations) foreach (Reservation reservation in reservations)
{ {
@@ -1009,28 +1261,74 @@ internal class Program
"Command: "); "Command: ");
while (true) while (true)
{ {
/*
* This is the main administrator loop.
* The following are valid operations:
*
* generate management report:
* Generates a series of report detailing the expected occupancy, expected room income,
* and the losses incurred due to incentive reservations. For more information see the
* GenerateManagementReport() function.
*
* generate operational report:
* Generates a series of reports detailing the daily arrivals and daily occupancy.
* For more information see the GenerateOperationalReports() function.
*
* generate accommodation bills:
* Generates the accommodation bills for reservations arriving that day. These will
* be handed out upon checkout (No process for this since there is no printer
* connected to this application). For more information see the GenerateAccommodationBills()
* function.
*
* notify pending payments:
* Generates an email for any outstanding payments within the payment window for
* 60-day-in-advance reservations. For more information see the NotifyOutstandingPayments()
* function.
*
* issue penalties:
* Issues penalties to reservations that end up as "no-show". Furthermore, it will
* also charge them if applicable. This is mostly just to pick up any reservations
* that are not canceled by users or canceled as a result of attempting to checkin
* or pay for a reservation that would be market as "no-show". For more information
* see the IssuePenalties() function.
*
* checkin guest:
* Checks in the guest and assigns them a room number. For more information see the
* CheckIn() function.
*
* checkout guest:
* Checks a guest out and marks their reservation as ended. The room number is
* not removed for historical purposes. For more information see the CheckOut()
* function.
*
* set rate:
* Set rate allows employees to set a specific rate for a specific day. This
* rate takes effect on the date set. For more information see the SetFutureBaseRate()
* function.
*
* Q or Q:
* Returns to the main loop for choosing either the Guest or Admin flow.
*/
string? input = Console.ReadLine(); string? input = Console.ReadLine();
switch (input) switch (input)
{ {
case "help": help(); break; case "help": help(); break; // Gets help text
case "generate management report": GenerateManagementReports(); break; case "generate management report": GenerateManagementReports(); break; // Generates management reports and outputs to text files
case "generate operational report": GenerateOperationalReports(); break; case "generate operational report": GenerateOperationalReports(); break; // Generates operational reports and outputs to text files
case "generate accommodation bills": GenerateAccommodationBills(); break; case "generate accommodation bills": GenerateAccommodationBills(); break; // Generates accommodation bills and outputs to a text file
case "notify pending payments": NotifyOutstandingPayments(); break; case "notify pending payments": NotifyOutstandingPayments(); break; // Generates an email and outputs to a text file
case "issue penalties": IssuePenalties(); break; case "issue penalties": IssuePenalties(); break; // Cancels "no-show" reservations and charges their accounts
case "checkin guest": CheckIn(); break; case "checkin guest": CheckIn(); break; // Checks a guest in and assigns a room
case "checkout guest": CheckOut(); break; case "checkout guest": CheckOut(); break; // Checks out a guest and marks their reservation as ended
case "set rate": SetFutureBaseRate(); break; case "set rate": SetFutureBaseRate(); break; // Allows employees to configure base rates
case "Q": return; case "Q": return; // Quit to mode loop
case "q": return; case "q": return; // Quit to mode loop
default: Console.WriteLine("Unknown command, enter help for more inforamtion."); break; default: Console.WriteLine("Unknown command, enter help for more inforamtion."); break;
} }
Console.Write("\nCommand: "); Console.Write("\nCommand: ");
} }
} }
private static void Main() private static void Main()
{ {
if (!File.Exists("database.sqlite3") || new FileInfo("database.sqlite3").Length == 0) if (!File.Exists("database.sqlite3") || new FileInfo("database.sqlite3").Length == 0)