1373 lines
64 KiB
C#
1373 lines
64 KiB
C#
using Ophelias.Expressions;
|
|
using Ophelias.Managers;
|
|
using Ophelias.Models;
|
|
using Ophelias.Reporting;
|
|
using System.Data.SQLite;
|
|
|
|
internal class Program
|
|
{
|
|
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: ");
|
|
string Email = "";
|
|
while (!Validation.ValidateEmail(Email))
|
|
{
|
|
Email = Console.ReadLine();
|
|
if (!Validation.ValidateEmail(Email))
|
|
{
|
|
Console.Write("Please enter a valid email: ");
|
|
}
|
|
}
|
|
return Email;
|
|
}
|
|
|
|
private static void GuestMode()
|
|
{
|
|
/*
|
|
* 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()
|
|
{
|
|
/*
|
|
* 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(
|
|
"Reservation Commands:\n" +
|
|
"\treservation create - Create a new reservation.\n" +
|
|
"\treservation update - Update your active reservation.\n" +
|
|
"\treservation cancel - Cancel a reservation.\n" +
|
|
"\treservation pay - Pays in full for an active reservation.\n" +
|
|
"Account Commands:\n" +
|
|
"\taccount create - Create a new guest account.\n" +
|
|
"\taccount update - Update your account information.\n" +
|
|
"\taccount login - Log into your guest account." +
|
|
"Enter Q or q to quit.\n"
|
|
);
|
|
return;
|
|
}
|
|
(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: ");
|
|
string CreditCard = "";
|
|
while (!Validation.ValidateCreditCard(CreditCard))
|
|
{
|
|
CreditCard = Console.ReadLine().Trim().Replace("\t", "");
|
|
if (CreditCard == "q" || CreditCard == "Q")
|
|
{
|
|
return (null, null, null);
|
|
}
|
|
|
|
if (!Validation.ValidateCreditCard(CreditCard))
|
|
{
|
|
Console.Write("Please enter a valid credit card. If your card is expired, enter Q to cancel: ");
|
|
}
|
|
}
|
|
Console.Write("What is your credit card expiration date (MM/yy): ");
|
|
string CardExpiration = "";
|
|
while (!Validation.ValidateExpirationDate(CardExpiration))
|
|
{
|
|
CardExpiration = Console.ReadLine().Trim().Replace("\t", "");
|
|
if (CardExpiration == "q" || CardExpiration == "Q")
|
|
{
|
|
return (null, null, null);
|
|
}
|
|
|
|
if (!Validation.ValidateExpirationDate(CardExpiration))
|
|
{
|
|
Console.Write("Please enter a valid expiration date. If your card is expired, enter Q to cancel: ");
|
|
}
|
|
}
|
|
Console.Write("What is your credit card CCV: ");
|
|
string CCV = "";
|
|
while (!Validation.ValidateCCV(CCV))
|
|
{
|
|
CCV = Console.ReadLine().Trim().Replace("\t", "");
|
|
if (CCV == "q" || CCV == "Q")
|
|
{
|
|
return (null, null, null);
|
|
}
|
|
|
|
if (!Validation.ValidateCCV(CCV))
|
|
{
|
|
Console.Write("Please enter a valid credit card CCV. If your card is expired, enter Q to cancel: ");
|
|
}
|
|
}
|
|
return (CreditCard, CardExpiration, CCV);
|
|
}
|
|
(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: ");
|
|
string FirstName = "";
|
|
while (FirstName.Length == 0)
|
|
{
|
|
FirstName = Console.ReadLine();
|
|
if (FirstName == "")
|
|
{
|
|
Console.Write("What is your first name: ");
|
|
}
|
|
}
|
|
Console.Write("What is your last name: ");
|
|
string LastName = "";
|
|
while (LastName.Length == 0)
|
|
{
|
|
LastName = Console.ReadLine();
|
|
if (LastName == "")
|
|
{
|
|
Console.Write("What is your last name: ");
|
|
}
|
|
}
|
|
return (FirstName, LastName);
|
|
}
|
|
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: ");
|
|
string 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();
|
|
if (!Validation.ValidateEmail(email))
|
|
{
|
|
Console.Write("Please enter a valid email: ");
|
|
}
|
|
}
|
|
activeGuest = Hotel.GetGuestByEmail(email);
|
|
if (activeGuest == null)
|
|
{
|
|
Console.WriteLine($"\nNo account was found with the email {email}.");
|
|
return;
|
|
}
|
|
Console.WriteLine($"\nYou have logged into {activeGuest.FirstName} {activeGuest.LastName} ({email}).");
|
|
activeReservation = Hotel.GetResByGuest(activeGuest);
|
|
}
|
|
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 Email = GetGuestEmail();
|
|
Console.Write("Would you like to enter your credit card details? (Y/n): ");
|
|
string? CreditCard = null;
|
|
string? CardExpiration = null;
|
|
string? CCV = null;
|
|
while (true)
|
|
{
|
|
string input = Console.ReadLine();
|
|
if (input.Equals("y") || input.Equals("Y"))
|
|
{
|
|
(CreditCard, CardExpiration, CCV) = GetCreditCardInformation();
|
|
break;
|
|
}
|
|
else if (input.Equals("n") || input.Equals("N"))
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
Console.Write("Input must be Y, y or N, n: ");
|
|
}
|
|
}
|
|
|
|
activeGuest = new(FirstName, LastName, Email, CreditCard: CreditCard, Expiration: CardExpiration, CCV: CCV);
|
|
Console.Write($"You are now logged in as {FirstName} {LastName} ({Email})");
|
|
}
|
|
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)
|
|
{
|
|
Console.WriteLine("No guest is currently logged in, please login.");
|
|
return;
|
|
}
|
|
|
|
string? NewFname = null, NewLname = null, NewEmail = null, NewCard = null, NewExpiry = null, NewCCV = null;
|
|
|
|
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)
|
|
{
|
|
Console.WriteLine("No changes have been made.");
|
|
return;
|
|
}
|
|
string changes = "";
|
|
List<string> NewDetails = new();
|
|
if (!string.IsNullOrEmpty(NewFname))
|
|
{
|
|
NewDetails.Add($"\tFirst Name: {activeGuest.FirstName} -> {NewFname}");
|
|
activeGuest.FirstName = NewFname;
|
|
}
|
|
if (!string.IsNullOrEmpty(NewLname))
|
|
{
|
|
NewDetails.Add($"\tLast Name: {activeGuest.LastName} -> {NewLname}");
|
|
activeGuest.LastName = NewLname;
|
|
}
|
|
if (!string.IsNullOrEmpty(NewEmail))
|
|
{
|
|
NewDetails.Add($"\tEmail: {activeGuest.Email} -> {NewEmail}");
|
|
activeGuest.Email = NewEmail;
|
|
}
|
|
if (!string.IsNullOrEmpty(NewCard))
|
|
{
|
|
NewDetails.Add($"\tCredit Card: {activeGuest.CreditCard} -> {NewCard}");
|
|
activeGuest.CreditCard = NewCard;
|
|
}
|
|
if (!string.IsNullOrEmpty(NewExpiry))
|
|
{
|
|
NewDetails.Add($"\tCard Expiration Date: {activeGuest.Expiration} -> {NewExpiry}");
|
|
activeGuest.Expiration = NewExpiry;
|
|
}
|
|
if (!string.IsNullOrEmpty(NewCCV))
|
|
{
|
|
NewDetails.Add($"\tCard CCV: {activeGuest.CCV} -> {NewCCV}");
|
|
activeGuest.CCV = NewCCV;
|
|
}
|
|
if (NewDetails.Count > 0)
|
|
{
|
|
changes += string.Join("\n", NewDetails);
|
|
}
|
|
|
|
Console.WriteLine($"The following changes have been made:\n {changes}");
|
|
activeGuest.UpdateGuest(activeGuest.Id, NewFname, NewLname, NewEmail, NewCard, NewExpiry, NewCCV);
|
|
activeReservation.Guest = activeGuest;
|
|
return;
|
|
}
|
|
|
|
Console.WriteLine($"You are currently logged in as {activeGuest.FirstName} {activeGuest.LastName} ({activeGuest.Email}).\n" +
|
|
$"If this is not your account, please (Q)uit and log into your account. Changes will be recorded, but not saved\n" +
|
|
$"until you enter S.\n");
|
|
|
|
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" +
|
|
"1. First Name and Last Name\n" +
|
|
"2. Email Address\n" +
|
|
"3. Credit Card Information\n");
|
|
switch (Console.ReadLine())
|
|
{
|
|
case "q": return;
|
|
case "Q": return;
|
|
case "1": (NewFname, NewLname) = GetGuestName(); break;
|
|
case "2": NewEmail = GetGuestEmail(); break;
|
|
case "3": (NewCard, NewExpiry, NewCCV) = GetCreditCardInformation(); break;
|
|
case "S": SavePrompt(); return;
|
|
default: break;
|
|
}
|
|
} while (true);
|
|
}
|
|
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 = "";
|
|
Console.Write("What kind of reservation would you like to make?\n" +
|
|
"1. Conventional\n" +
|
|
"2. Prepaid\n" +
|
|
"3. 60 Day Advance\n" +
|
|
"4. Incentive\n" +
|
|
"Input a number: ");
|
|
while (true)
|
|
{
|
|
input = Console.ReadLine();
|
|
if (input == "1" || input == "2" || input == "3" || input == "4")
|
|
{
|
|
break;
|
|
}
|
|
|
|
Console.Write("Please enter either 1, 2, 3, or 4: ");
|
|
}
|
|
return (ReservationType)(Convert.ToInt32(input) - 1);
|
|
}
|
|
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 ((int)(Date - DateTime.Now).TotalDays < 90)
|
|
{
|
|
Console.WriteLine("Prepaid reservations must be made 90 days in advance.");
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
else if (Type == ReservationType.SixtyDayAdvance)
|
|
{
|
|
if ((int)(Date - DateTime.Now).TotalDays < 60)
|
|
{
|
|
Console.WriteLine("Sixty-days-in-advance reservations must be made 60 days in advance.");
|
|
}
|
|
else
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
(DateTime?, DateTime?) SelectDate(ReservationType Type)
|
|
{
|
|
|
|
(DateTime, DateTime) Dates()
|
|
{
|
|
string input = "";
|
|
DateTime _StartDate;
|
|
DateTime _EndDate;
|
|
Console.Write("When would you like to begin your stay.\n" +
|
|
"Your date input should be in in the following format - yyyy-MM-dd. Example: (2021-12-31)?\n" +
|
|
"Input a date (2021-12-31): ");
|
|
while (true)
|
|
{
|
|
input = Console.ReadLine();
|
|
if (DateTime.TryParse(input, out _StartDate) && _StartDate >= DateTime.Now)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (_StartDate <= DateTime.Now)
|
|
{
|
|
Console.Write("Start date cannot be before current date. Please enter a valid date (2021-12-31): ");
|
|
}
|
|
else
|
|
{
|
|
Console.Write("Please enter a valid date (2021-12-31): ");
|
|
}
|
|
}
|
|
Console.Write("When would you like to end your stay.\n" +
|
|
"Your date input should be in in the following format - yyyy-MM-dd. Example: (2021-12-31)?\n" +
|
|
"Input a date (2021-12-31): ");
|
|
while (true)
|
|
{
|
|
input = Console.ReadLine();
|
|
if (DateTime.TryParse(input, out _EndDate) && _EndDate > _StartDate)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (_EndDate < _StartDate)
|
|
{
|
|
Console.Write("End date must be after start date. Please enter a valid date (2021-12-31): ");
|
|
}
|
|
else
|
|
{
|
|
Console.Write("Please enter a valid date (2021-12-31): ");
|
|
}
|
|
}
|
|
return (_StartDate.Date, _EndDate.Date);
|
|
}
|
|
|
|
DateTime StartDate;
|
|
DateTime EndDate;
|
|
string input;
|
|
|
|
while (true)
|
|
{
|
|
bool maxCapacity = false;
|
|
(StartDate, EndDate) = Dates();
|
|
if (StartDate == null || EndDate == null)
|
|
{
|
|
(_, maxCapacity) = Hotel.AvgOccupancySpan(StartDate, EndDate);
|
|
}
|
|
|
|
if (!maxCapacity)
|
|
{
|
|
if (!CheckReservationRestrictions(StartDate, Type))
|
|
{
|
|
Console.Write("Do you want to quit? Type YES to quit and discard, enter anything or nothing to select another date range.\n" +
|
|
": ");
|
|
input = Console.ReadLine();
|
|
if (input == "YES")
|
|
{
|
|
Console.WriteLine("Aborting reservation changes.");
|
|
return (null, null);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("Your reservation covers a range where we are already at max capacity, please change your reservation dates.");
|
|
}
|
|
|
|
}
|
|
return (StartDate, EndDate);
|
|
|
|
}
|
|
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)
|
|
{
|
|
Console.WriteLine("No guest is currently logged in, please login.");
|
|
return;
|
|
}
|
|
if (activeReservation != null)
|
|
{
|
|
Console.WriteLine("You currently have an active registration.");
|
|
return;
|
|
}
|
|
if (Hotel.GetBaseRate() == null)
|
|
{
|
|
Console.WriteLine("Unable to proceed with reservation due to no base rate being set. Please inform an employee.");
|
|
return;
|
|
}
|
|
|
|
string input;
|
|
|
|
ReservationType Type;
|
|
DateTime? StartDate;
|
|
DateTime? EndDate;
|
|
|
|
Type = SelectReservation();
|
|
(StartDate, EndDate) = SelectDate(Type);
|
|
if (StartDate == null || EndDate == null)
|
|
{
|
|
Console.WriteLine("Aborting reservation creation.");
|
|
return;
|
|
}
|
|
|
|
while ((Type != ReservationType.SixtyDayAdvance &&
|
|
(activeGuest.CreditCard == null || activeGuest.Expiration == null || activeGuest.CCV == null)))
|
|
{
|
|
Console.Write("The reservation type you chose requires you to specify your credit card.\n" +
|
|
"If you are unable to provide one, enter Q to quit or hit enter to continue.\n" +
|
|
": ");
|
|
input = Console.ReadLine();
|
|
if (input == "Q")
|
|
{
|
|
return;
|
|
}
|
|
|
|
GetCreditCardInformation();
|
|
}
|
|
|
|
Console.Write($"Thank you for filling out your reservation details. Currently you have made a {Type} " +
|
|
$"reservation and are scheduled to stay from {StartDate.Value.ToString("yyyy-MM-dd")} to {EndDate.Value.ToString("yyyy-MM-dd")}." +
|
|
$"If these details are correct, enter YES to complete. To cancel your reservation enter Q.\n" +
|
|
$": ");
|
|
input = Console.ReadLine();
|
|
while (input != "YES")
|
|
{
|
|
if (input == "Q")
|
|
{
|
|
Console.WriteLine("Reservation has been deleted.");
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
Console.Write("Input must be YES or Q.\n: ");
|
|
input = Console.ReadLine();
|
|
}
|
|
}
|
|
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.Transaction.Pay(activeReservation.Transaction.Owed, activeGuest.CreditCard);
|
|
}
|
|
else // Creates a new reservation and set it as the active.
|
|
{
|
|
activeReservation = new(activeGuest, Type, DateTime.Now.Date, StartDate.Value, EndDate.Value);
|
|
}
|
|
Console.WriteLine("Your reservation has been made.");
|
|
}
|
|
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";
|
|
if (activeGuest == null)
|
|
{
|
|
Console.WriteLine("No guest is currently logged in, please login.");
|
|
return;
|
|
}
|
|
if (activeReservation == null)
|
|
{
|
|
Console.WriteLine("You currently do not have an active registration.");
|
|
return;
|
|
}
|
|
|
|
Console.Write("Your current reservation details are:\n" +
|
|
$"\tStarts on: {activeReservation.StartDate.ToString("yyyy-MM-dd")}\n" +
|
|
$"\tEnds on: {activeReservation.EndDate.ToString("yyyy-MM-dd")}\n");
|
|
DateTime? _StartDate = null, _EndDate = null;
|
|
do
|
|
{
|
|
if (input == "NO")
|
|
{
|
|
(_StartDate, _EndDate) = SelectDate(activeReservation.Type);
|
|
if (_StartDate.HasValue && _EndDate.HasValue)
|
|
{
|
|
Console.Write("Your new reservation details are:\n" +
|
|
$"\tStarts on: {activeReservation.StartDate.ToString("yyyy-MM-dd")} -> {_StartDate.Value.ToString("yyyy-MM-dd")}\n" +
|
|
$"\tEnds on: {activeReservation.EndDate.ToString("yyyy-MM-dd")} -> {_EndDate.Value.ToString("yyyy-MM-dd")}\n");
|
|
}
|
|
|
|
Console.Write("Are you done with your changes?\n" +
|
|
"Enter YES to finish and save, NO to continue editing.\n" +
|
|
": ");
|
|
}
|
|
else if (input == "Q")
|
|
{
|
|
Console.WriteLine("Your changes have been discarded.");
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("Input must be YES, NO, or Q.");
|
|
Console.Write(": ");
|
|
}
|
|
input = Console.ReadLine();
|
|
} while (input != "YES");
|
|
if (_StartDate != null && _EndDate != null)
|
|
{
|
|
activeReservation.ChangeReservationDates((DateTime)_StartDate, (DateTime)_EndDate);
|
|
Console.WriteLine("Your changes have been saved.");
|
|
}
|
|
return;
|
|
}
|
|
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)
|
|
{
|
|
Console.WriteLine("No guest is currently logged in, please login.");
|
|
return;
|
|
}
|
|
if (activeReservation == null)
|
|
{
|
|
Console.WriteLine("You currently do not have an active registration.");
|
|
return;
|
|
}
|
|
string input;
|
|
Console.Write("Would you like to cancel your reservation?\n" +
|
|
"You may be charged depending on your reservation.\n" +
|
|
"Enter YES to confirm or NO to exit: ");
|
|
input = Console.ReadLine();
|
|
while (input != "YES")
|
|
{
|
|
if (input == "NO")
|
|
{
|
|
Console.Write("Reservation has not been cancelled.");
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
Console.Write("Your input must be YES or NO: ");
|
|
Console.ReadLine();
|
|
}
|
|
}
|
|
activeReservation.CancelReservation();
|
|
activeReservation = null;
|
|
Console.Write("Reservation has been cancelled, you may be charged based on your reservation.");
|
|
}
|
|
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)
|
|
{
|
|
Console.WriteLine("No guest is currently logged in, please login.");
|
|
return;
|
|
}
|
|
if (activeReservation == null)
|
|
{
|
|
Console.WriteLine("You currently do not have an active registration.");
|
|
return;
|
|
}
|
|
|
|
if (ReservationType.Incentive == activeReservation.Type)
|
|
{
|
|
Console.WriteLine("Incentive reservations are paid for when you check-out.");
|
|
return;
|
|
}
|
|
else if (ReservationType.Conventional == activeReservation.Type)
|
|
{
|
|
Console.WriteLine("Conventional reservations are paid for when you check-out.");
|
|
return;
|
|
}
|
|
else if (ReservationType.Prepaid == activeReservation.Type)
|
|
{
|
|
Console.WriteLine("Prepaid reservations are paid for when you create them.");
|
|
return;
|
|
} 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.Transaction.Owed <= activeReservation.Transaction.AmountPaid)
|
|
{
|
|
Console.WriteLine("Your reservation has already been paid for.");
|
|
return;
|
|
}
|
|
activeReservation.CancelReservation();
|
|
Console.WriteLine("Your reservation has been cancelled because you failed to pay within the payment period.");
|
|
return;
|
|
}
|
|
}
|
|
|
|
string? cc, exp, ccv;
|
|
cc = activeGuest.CreditCard;
|
|
exp = activeGuest.Expiration;
|
|
ccv = activeGuest.CCV;
|
|
while (true)
|
|
{
|
|
/*
|
|
* 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) // 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" +
|
|
"YES or NO: ");
|
|
while (true)
|
|
{
|
|
string input = Console.ReadLine();
|
|
if (input == "YES")
|
|
{
|
|
break;
|
|
} else if (input == "NO")
|
|
{
|
|
Console.WriteLine("Payment has been aborted.");
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
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)
|
|
{
|
|
/*
|
|
* 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)))
|
|
{
|
|
Console.WriteLine("Your card expires too soon. Please enter the correct expiration date if incorrect or a new card.");
|
|
cc = null;
|
|
exp = null;
|
|
ccv = null;
|
|
}
|
|
else if (ReservationType.SixtyDayAdvance == activeReservation.Type && ((DateTime.Parse(exp).Date > activeReservation.StartDate.AddDays(-30).Date) && (DateTime.Parse(exp).Date > activeReservation.StartDate.AddDays(-45).Date)))
|
|
{
|
|
if (cc != activeGuest.CreditCard && exp != activeGuest.Expiration && ccv != activeGuest.CCV)
|
|
{
|
|
activeGuest.UpdateGuest(activeGuest.Id, CreditCard: cc, Expiration: exp, CCV: ccv);
|
|
activeReservation.Guest = activeGuest;
|
|
}
|
|
PaymentStatus ps = activeReservation.Transaction.Pay(activeReservation.Transaction.Owed, activeGuest.CreditCard);
|
|
if (ps == PaymentStatus.SuccessfulPayment)
|
|
{
|
|
Console.WriteLine("Your reservation has been paid for.");
|
|
return;
|
|
} else if (ps == PaymentStatus.FailedPayment)
|
|
{
|
|
Console.WriteLine("There was an error paying for your resevation. Try again later or contact the Ophelias Oasis team.");
|
|
return;
|
|
} else if (ps == PaymentStatus.AmountCannotZero)
|
|
{
|
|
Console.WriteLine("You cannot pay $0 or less than $0.");
|
|
return;
|
|
} else if (ps == PaymentStatus.MissingCreditCard)
|
|
{
|
|
Console.WriteLine("Credit Card information is missing. Payment could not be made.");
|
|
} else if (ps == PaymentStatus.AlreadyPaid)
|
|
{
|
|
Console.WriteLine("Your reservation has already been paid for.");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
Console.Write(
|
|
"\nWelcome to the Ophelias Oasis Hotel Registration System!\n" +
|
|
"Type help to get a full list of commands or enter a command.\n" +
|
|
"Command: "
|
|
);
|
|
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();
|
|
switch (input)
|
|
{
|
|
case "help": help(); break; // Gets help text
|
|
case "reservation create": CreateNewReservation(); break; // Allows guests to create a reservation
|
|
case "reservation update": UpdateReservation(); break; // Allows guests to update a reservation if they have one
|
|
case "reservation cancel": CancelReservation(); break; // Allows guests to cancel a reservation if they have one
|
|
case "reservation pay": PayForReservation(); break; // Allows guests with 60-day reservations to pay for it
|
|
case "account create": CreateNewGuestPrompt(); break; // Creates a new guest
|
|
case "account update": UpdateGuestInformation(); break; // Updates a guests personal and/ or payment information
|
|
case "account login": GuestLogin(); break; // Logs a guest in
|
|
case "q": return; // Quit to mode loop
|
|
case "Q": return; // Quit to mode loop
|
|
default: Console.WriteLine("Unknown command, enter help for more inforamtion."); break;
|
|
}
|
|
Console.Write("\nCommand: ");
|
|
}
|
|
}
|
|
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()
|
|
{
|
|
/*
|
|
* Help text to understand commands.
|
|
*/
|
|
Console.WriteLine(
|
|
"Report Commands:\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 accommodation bills - Generates an accommodation bill that will be handed to guests upon checkout.\n" +
|
|
"\nManagement Commands:\n" +
|
|
"\tnotify pending payments - Generates and emails 60 day advance reservations that they must pay for their reservation or it will be cancelled.\n" +
|
|
"\tissue penalties - Issues penalties for guests that are no shows.\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" +
|
|
"\tset rate - Sets a new base rate to begin after a specified date.\n" +
|
|
"\nEnter Q or q to quit.\n"
|
|
);
|
|
return;
|
|
}
|
|
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)
|
|
{
|
|
/*
|
|
* 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 amount;
|
|
amount = Console.ReadLine();
|
|
if (Validation.ValidateMoney(amount))
|
|
{
|
|
Console.Write($"Is this the correct base rate {amount}?\n" +
|
|
$"Enter YES or NO: ");
|
|
input = Console.ReadLine();
|
|
while (input != "YES")
|
|
{
|
|
if (input == "NO")
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
Console.Write("Input must be YES or NO: ");
|
|
}
|
|
input = Console.ReadLine();
|
|
}
|
|
if (input == "YES")
|
|
{
|
|
if (FixedDate != null)
|
|
{
|
|
if (Hotel.GetBaseRateByDate((DateTime)FixedDate))
|
|
{
|
|
Console.Write("There is already a base rate configured for this date.\n" +
|
|
"If you are entering a new rate because one was not configured and got this error, type YES.\n" +
|
|
"Would you like to overwrite it (YES)? If not enter anything to continue.\n" +
|
|
": ");
|
|
if (Console.ReadLine() == "YES")
|
|
{
|
|
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;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
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.");
|
|
}
|
|
else
|
|
{
|
|
DateTime StartDate;
|
|
Console.Write("When would you like the new rate to take effect.\n" +
|
|
"Your date input should be in in the following format - yyyy-MM-dd. Example: (2021-12-31)?\n" +
|
|
"Input a date (2021-12-31): ");
|
|
while (true)
|
|
{
|
|
input = Console.ReadLine();
|
|
if (DateTime.TryParse(input, out StartDate))
|
|
{
|
|
if (StartDate.Date <= DateTime.Now.Date)
|
|
{
|
|
Console.WriteLine("Base rate must be configured for a future night. Not the same day or past.");
|
|
}
|
|
else if (Hotel.GetBaseRateByDate(StartDate))
|
|
{
|
|
Console.Write("There is already a base rate configured for this date.\n" +
|
|
"Would you like to overwrite it (YES)? If not enter anything to continue." +
|
|
": ");
|
|
if (Console.ReadLine() == "YES")
|
|
{
|
|
Hotel.UpdateBaseRate(Convert.ToDouble(amount), StartDate.Date); // Replaces the existing base rate with a new value if the date matches.
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
Console.Write("Please enter a valid date (2021-12-31): ");
|
|
}
|
|
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")}.");
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine("Your input was not a valid input, an example of a valid input would be 100 or 100.00.");
|
|
}
|
|
Console.Write("Enter new rate: ");
|
|
return false;
|
|
}
|
|
|
|
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. " +
|
|
"You must set one for the current date.\n" +
|
|
"Enter new rate: ");
|
|
while (!SetRatePrompt(DateTime.Now.Date)) { } // Continues to loop until a base rate is successfully configured.
|
|
}
|
|
else
|
|
{
|
|
Console.Write("What is the value of the rate you would like to set.\n" +
|
|
"Enter new rate: ");
|
|
while (!SetRatePrompt()) { } // Continues to loop until a base rate is successfully configured.
|
|
}
|
|
}
|
|
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();
|
|
TimeRefs? status = Hotel.CanBeCheckedIn(Email);
|
|
Guest? g = Hotel.GetGuestByEmail(Email);
|
|
if (g == null)
|
|
{
|
|
Console.WriteLine("No guest with that email exists.");
|
|
return;
|
|
}
|
|
if (!status.HasValue)
|
|
{
|
|
Console.WriteLine("No reservation exists for this email.");
|
|
return;
|
|
}
|
|
|
|
if (status.Value == TimeRefs.OnTime)
|
|
{
|
|
int? RoomID = Hotel.CheckInGuest(Email, DateTime.Now.Date);
|
|
if (RoomID != null)
|
|
{
|
|
Console.WriteLine($"Guest has been checked in, their room number is {RoomID}.");
|
|
}
|
|
}
|
|
else if (status.Value == TimeRefs.Late)
|
|
{
|
|
Console.WriteLine("Since the reservation was not checked in on the date scheduled, it has been cancelled. The guest will be charged the \"no show\" penalty.");
|
|
Reservation? r = Hotel.GetResByGuest(g);
|
|
|
|
if (r == null)
|
|
{
|
|
throw new Exception();
|
|
}
|
|
|
|
r.CancelReservation();
|
|
|
|
}
|
|
else if (status.Value == TimeRefs.Early)
|
|
{
|
|
Console.WriteLine("Since the reservation was not checked in on the date scheduled, it has been cancelled. The guest will be charged the \"no show\" penalty.");
|
|
}
|
|
return;
|
|
}
|
|
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();
|
|
if (Hotel.GuestCurrentlyCheckedIn(Email))
|
|
{
|
|
Reservation r = Hotel.GetResByGuest(Hotel.GetGuestByEmail(Email));
|
|
if (r.Type == ReservationType.Incentive || r.Type == ReservationType.Conventional)
|
|
{
|
|
r.Transaction.Pay(r.Transaction.Owed, r.Guest.CreditCard);
|
|
}
|
|
|
|
Hotel.CheckOutGuest(Email, DateTime.Now.Date);
|
|
Console.WriteLine($"Guest has been checked out.");
|
|
}
|
|
else
|
|
{
|
|
Console.WriteLine($"Can't checkout a guest that hasn't been checked in.");
|
|
}
|
|
return;
|
|
}
|
|
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();
|
|
foreach (Reservation r in activeSixtyRes)
|
|
{
|
|
int days = (int)(r.StartDate.Date - DateTime.Now.Date).TotalDays - 30;
|
|
if (days < 0)
|
|
{
|
|
r.CancelReservation();
|
|
}
|
|
else if (days <= 15)
|
|
{
|
|
Email e = new(r.Guest.Email);
|
|
e.Send();
|
|
}
|
|
}
|
|
if (File.Exists("Emails.txt") && activeSixtyRes.Count != 0)
|
|
{
|
|
FileInfo f = new("Emails.txt");
|
|
Console.WriteLine($"Emails have been written and appended to {f.FullName}");
|
|
} else
|
|
{
|
|
Console.WriteLine("There are no emails to send.");
|
|
}
|
|
}
|
|
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();
|
|
Management.CalculateExpectedOccupancy(w.Item2, w.Item1);
|
|
if (File.Exists("ExpectedOccupancy.txt"))
|
|
{
|
|
FileInfo f = new("ExpectedOccupancy.txt");
|
|
Console.WriteLine($"Expected occupancy has been written and appended to {f.FullName}");
|
|
}
|
|
var x = Hotel.GetExpectedIncomeCount();
|
|
Management.CalculateExpectedIncome(x.Item1, x.Item2, x.Item3);
|
|
if (File.Exists("ExpectedIncome.txt"))
|
|
{
|
|
FileInfo f = new("ExpectedIncome.txt");
|
|
Console.WriteLine($"Expected income has been written and appended to {f.FullName}");
|
|
}
|
|
var y = Hotel.GetIncentiveTransactions();
|
|
Management.CalculateIncentiveLosses(y.Item3, y.Item1, y.Item2);
|
|
if (File.Exists("IncentiveLosses.txt"))
|
|
{
|
|
FileInfo f = new("IncentiveLosses.txt");
|
|
Console.WriteLine($"Incentive losses have been written and appended to {f.FullName}");
|
|
}
|
|
}
|
|
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();
|
|
|
|
if (reservations.Count == 0)
|
|
{
|
|
Console.WriteLine($"No accommodation bills to generate.");
|
|
return;
|
|
}
|
|
|
|
Accommodation.GenerateAccommodationBills(reservations);
|
|
|
|
if (File.Exists("AccommodationBills.txt"))
|
|
{
|
|
FileInfo f = new("AccommodationBills.txt");
|
|
Console.WriteLine($"Accommodation bills have been written and appended to {f.FullName}");
|
|
}
|
|
}
|
|
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();
|
|
|
|
if (reservations.Count == 0)
|
|
{
|
|
Console.WriteLine($"No daily arrivals to report.");
|
|
} else
|
|
{
|
|
Operational.FetchDailyArriavals(reservations);
|
|
if (File.Exists("DailyArrivals.txt"))
|
|
{
|
|
FileInfo f = new("DailyArrivals.txt");
|
|
Console.WriteLine($"Daily arrivals have been written and appended to {f.FullName}");
|
|
}
|
|
}
|
|
|
|
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);
|
|
if (File.Exists("DailyOccupancy.txt"))
|
|
{
|
|
FileInfo f = new("DailyOccupancy.txt");
|
|
Console.WriteLine($"Daily occupancy has been written and appended to {f.FullName}");
|
|
}
|
|
}
|
|
}
|
|
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();
|
|
foreach (Reservation reservation in reservations)
|
|
{
|
|
reservation.CancelReservation();
|
|
}
|
|
Console.WriteLine("Penalties have been issued.");
|
|
}
|
|
|
|
Console.Write(
|
|
"\nWelcome to the Ophelias Oasis Hotel Management System!\n" +
|
|
"Type help to get a full list of commands or enter a command.\n" +
|
|
"Command: ");
|
|
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();
|
|
switch (input)
|
|
{
|
|
case "help": help(); break; // Gets help text
|
|
case "generate management report": GenerateManagementReports(); break; // Generates management reports and outputs to text files
|
|
case "generate operational report": GenerateOperationalReports(); break; // Generates operational reports and outputs to text files
|
|
case "generate accommodation bills": GenerateAccommodationBills(); break; // Generates accommodation bills and outputs to a text file
|
|
case "notify pending payments": NotifyOutstandingPayments(); break; // Generates an email and outputs to a text file
|
|
case "issue penalties": IssuePenalties(); break; // Cancels "no-show" reservations and charges their accounts
|
|
case "checkin guest": CheckIn(); break; // Checks a guest in and assigns a room
|
|
case "checkout guest": CheckOut(); break; // Checks out a guest and marks their reservation as ended
|
|
case "set rate": SetFutureBaseRate(); break; // Allows employees to configure base rates
|
|
case "Q": return; // Quit to mode loop
|
|
case "q": return; // Quit to mode loop
|
|
default: Console.WriteLine("Unknown command, enter help for more inforamtion."); break;
|
|
}
|
|
Console.Write("\nCommand: ");
|
|
}
|
|
|
|
}
|
|
private static void Main()
|
|
{
|
|
if (!File.Exists("database.sqlite3") || new FileInfo("database.sqlite3").Length == 0)
|
|
{
|
|
/*
|
|
* Checks to see if the databse is created. If the database file is missing, that means
|
|
* it has not been initialized. Upon the initialization process, the tables are created
|
|
* and the rooms table is populated with 45 rooms. This is a preconfigured value within
|
|
* the InitializeRoomsTable() function since there was no requirement to make this configurable.
|
|
*/
|
|
SQLiteConnection.CreateFile("database.sqlite3");
|
|
using Database Manager = new();
|
|
Manager.InitializeTables();
|
|
Manager.InitializeRoomsTable();
|
|
}
|
|
if (!Hotel.CheckBaseRate())
|
|
{
|
|
// Checks to see if the base rate is configured, if not a warning will be shown.
|
|
Console.WriteLine("No base rate is configured. As a result reservations cannot be made until one is configured.");
|
|
}
|
|
|
|
bool run = true;
|
|
while (run)
|
|
{
|
|
// Main loop for checking if the person is a customer or employee.
|
|
Console.Write(
|
|
"Are you an employee or customer?\n" +
|
|
"1. Employee\n" +
|
|
"2. Customer/ Guest\n" +
|
|
": "
|
|
);
|
|
switch (Console.ReadLine().ToUpper()) // Using .ToUpper() to support "q" without having to write a case for it.
|
|
{
|
|
case "1": AdminMode(); break; // Enter employee (administrative) mode
|
|
case "2": GuestMode(); break; // Enter guest (customer) mode
|
|
case "Q": run = false; break; // Quit
|
|
default: Console.WriteLine("You must either specify 1 for Employee, 2 for Customer/ Guest, or Q to quit.\n\n"); break;
|
|
}
|
|
}
|
|
Console.WriteLine("Shutting system down.");
|
|
}
|
|
} |