307 lines
13 KiB
C#
307 lines
13 KiB
C#
using Ophelias.Managers;
|
|
using System.Data.SQLite;
|
|
|
|
namespace Ophelias.Models
|
|
{
|
|
internal class Transaction
|
|
{
|
|
/*
|
|
* This class is related to a specific reservation, however,
|
|
* the correlation is not two ways as a transaction is a
|
|
* member of the reservation but not the other way around.
|
|
* Reservations are related to transactions by their ID.
|
|
* The transaction class is comprised of the following:
|
|
*
|
|
* Id
|
|
* Unique identifier
|
|
*
|
|
* Rate
|
|
* The base rate set for the transaction
|
|
*
|
|
* Owed
|
|
* The total amount a user owes
|
|
*
|
|
* Penalty
|
|
* This is a legacy item but exists for future functionality where penalty amounts
|
|
* may be set
|
|
*
|
|
* Multiplier
|
|
* The fee multiplier based on reservation status or type, see TxFunctions
|
|
*
|
|
* RefundAmount
|
|
* The amount to be refunded, currently a legacy item that remained for potential
|
|
* future use
|
|
*
|
|
* AmountPaid
|
|
* The amount of money paid by a guest
|
|
*
|
|
* PayBy
|
|
* The date a transaction should be paid by at the latest
|
|
*
|
|
* LastPaid
|
|
* The date a payment was last made
|
|
*
|
|
* PaidOn
|
|
* The date the transaction was paid off (when Owed = AmountPaid)
|
|
*/
|
|
internal int Id;
|
|
internal double Rate;
|
|
internal double Owed;
|
|
internal double Penalty;
|
|
internal double Multiplier;
|
|
internal double RefundAmount;
|
|
internal double AmountPaid;
|
|
internal DateTime PayBy;
|
|
internal DateTime? LastPaid = null;
|
|
internal DateTime? PaidOn = null;
|
|
|
|
internal Transaction(double Rate, double Owed,
|
|
double Multiplier, DateTime PayBy, DateTime? LastPaid = null,
|
|
DateTime? PaidOn = null, double RefundAmount = 0, double Penalty = 0, double AmountPaid = 0)
|
|
{
|
|
/*
|
|
* Creates a new transaction based on the assumption it never existed before.
|
|
* This constructor will create a new transaction in the database and return
|
|
* the ID from the database insertion.
|
|
*/
|
|
int Id;
|
|
using (Database Manager = new()) // Create a new connection to the database
|
|
{
|
|
using (SQLiteCommand cmd = Manager.con.CreateCommand()) // Creates a new command that will be executed in the database
|
|
{
|
|
cmd.CommandText = "INSERT INTO transactions (Rate, Owed, Penalty, Multiplier, RefundAmount, AmountPaid, PayBy, LastPaid, PaidOn) " +
|
|
"VALUES (@Rate, @Owed, @Penalty, @Multiplier, @RefundAmount, @AmountPaid, @PayBy, @LastPaid, @PaidOn)";
|
|
cmd.Parameters.AddWithValue("@Rate", Rate);
|
|
cmd.Parameters.AddWithValue("@Owed", Owed);
|
|
cmd.Parameters.AddWithValue("@Multiplier", Multiplier);
|
|
cmd.Parameters.AddWithValue("@RefundAmount", RefundAmount);
|
|
cmd.Parameters.AddWithValue("@AmountPaid", AmountPaid);
|
|
cmd.Parameters.AddWithValue("@Penalty", Penalty);
|
|
cmd.Parameters.AddWithValue("@PayBy", PayBy.ToString("yyyy-MM-dd"));
|
|
cmd.Parameters.AddWithValue("@LastPaid", LastPaid);
|
|
cmd.Parameters.AddWithValue("@PaidOn", PaidOn);
|
|
if (LastPaid != null)
|
|
{
|
|
cmd.Parameters.AddWithValue("@LastPaid", LastPaid.Value.ToString("yyyy-MM-dd"));
|
|
}
|
|
else
|
|
{
|
|
cmd.Parameters.AddWithValue("@LastPaid", LastPaid);
|
|
}
|
|
|
|
if (PaidOn != null)
|
|
{
|
|
cmd.Parameters.AddWithValue("@PaidOn", PaidOn.Value.ToString("yyyy-MM-dd"));
|
|
}
|
|
else
|
|
{
|
|
cmd.Parameters.AddWithValue("@PaidOn", PaidOn);
|
|
}
|
|
|
|
cmd.ExecuteNonQuery();
|
|
}
|
|
Id = (int)Manager.con.LastInsertRowId; // Sets the ID based on the ID returned by database insertion
|
|
}
|
|
this.Id = Id;
|
|
this.Rate = Rate;
|
|
this.Owed = Owed;
|
|
this.Penalty = Penalty;
|
|
this.Multiplier = Multiplier;
|
|
this.RefundAmount = RefundAmount;
|
|
this.AmountPaid = AmountPaid;
|
|
this.PayBy = PayBy;
|
|
this.LastPaid = LastPaid;
|
|
this.PaidOn = PaidOn;
|
|
}
|
|
internal Transaction(int Id, double Rate, double Owed,
|
|
double Multiplier, DateTime PayBy, DateTime? LastPaid = null,
|
|
DateTime? PaidOn = null, double RefundAmount = 0, double Penalty = 0, double AmountPaid = 0)
|
|
{
|
|
/*
|
|
* Creates a new instance of transaction based on an existing transaction.
|
|
*/
|
|
this.Id = Id;
|
|
this.Rate = Rate;
|
|
this.Owed = Owed;
|
|
this.Penalty = Penalty;
|
|
this.Multiplier = Multiplier;
|
|
this.RefundAmount = RefundAmount;
|
|
this.AmountPaid = AmountPaid;
|
|
this.PayBy = PayBy;
|
|
this.LastPaid = LastPaid;
|
|
this.PaidOn = PaidOn;
|
|
}
|
|
|
|
internal void UpdateTransactionFees(double Rate, double Multiplier, DateTime PayBy)
|
|
{
|
|
/*
|
|
* This function is used in conjunction with Reservation's UpdateReservation function
|
|
* typically as this function updates a transaction with the new fees and PayBy date.
|
|
* These changes are stored on the existing model and written out to the database.
|
|
*/
|
|
this.Rate = Rate;
|
|
this.Multiplier = Multiplier;
|
|
this.PayBy = PayBy;
|
|
using Database Manager = new();
|
|
using SQLiteCommand cmd = Manager.con.CreateCommand();
|
|
string? query = QueryBuilder.UpdateTransaction(Id: Id, Rate: this.Rate, Multiplier: this.Multiplier, PayBy: this.PayBy); // Query string with parameters
|
|
|
|
if (query == null)
|
|
{
|
|
throw new Exception();
|
|
}
|
|
|
|
cmd.CommandText = query;
|
|
cmd.Parameters.AddWithValue("@ID", Id);
|
|
cmd.Parameters.AddWithValue("@Rate", this.Rate);
|
|
cmd.Parameters.AddWithValue("@Multiplier", this.Multiplier);
|
|
cmd.Parameters.AddWithValue("@PayBy", this.PayBy.ToString("yyyy-MM-dd"));
|
|
cmd.ExecuteNonQuery();
|
|
}
|
|
internal PaymentStatus Pay(double Amount, string cc)
|
|
{
|
|
/*
|
|
* This function attempts to make a payment based on the amount specified
|
|
* and if a creditcard exists. While we should be checking if the card is
|
|
* expired here, there are other systems further up the stack that prevent
|
|
* that from happening. Changes in the future would benefit us if we implement it
|
|
* down the line. Outside of that specific design, this class will return
|
|
* a payment status based on various conditions such as attempts to pay $0 or less,
|
|
* paying an already paid transaction and so forth. See the PaymentStatus enum for
|
|
* all the types which use self-explanatory names. Assuming payment is succesful,
|
|
* the AmountPaid is updated and the PaidOn date is set. These changes are then reflected
|
|
* to the database. Currently there is a refund parameter, however, it has not been
|
|
* implemented since refunds were not called for in the original design spec.
|
|
*/
|
|
|
|
// Series of checks to prevent payment on certain conditions
|
|
if (string.IsNullOrEmpty(cc))
|
|
{
|
|
return PaymentStatus.MissingCreditCard;
|
|
}
|
|
if (AmountPaid >= Owed)
|
|
{
|
|
return PaymentStatus.AlreadyPaid;
|
|
}
|
|
if (Amount <= 0)
|
|
{
|
|
return PaymentStatus.AmountCannotZero;
|
|
}
|
|
|
|
LastPaid = DateTime.Now;
|
|
AmountPaid += Amount;
|
|
if (Owed - AmountPaid < 0) // Calulates the refund amount if applicable
|
|
{
|
|
RefundAmount = Math.Abs(Owed - Amount);
|
|
}
|
|
|
|
if (Owed - AmountPaid <= 0) // Sets the paid by date
|
|
{
|
|
PaidOn = DateTime.Now;
|
|
}
|
|
|
|
using Database Manager = new(); // Opens a new database connection
|
|
using SQLiteCommand cmd = Manager.con.CreateCommand(); // Creates a new command that will be executed in the database
|
|
string? query = QueryBuilder.UpdateTransaction(Id: Id, Refund: RefundAmount, AmountPaid: AmountPaid, LastPaid: LastPaid, PaidOn: PaidOn); // Query string with parameters
|
|
|
|
if (query == null)
|
|
{
|
|
throw new Exception();
|
|
}
|
|
|
|
cmd.CommandText = query;
|
|
cmd.Parameters.AddWithValue("@ID", Id);
|
|
cmd.Parameters.AddWithValue("@RefundAmount", RefundAmount);
|
|
cmd.Parameters.AddWithValue("@AmountPaid", AmountPaid);
|
|
cmd.Parameters.AddWithValue("@LastPaid", LastPaid.Value.ToString("yyyy-MM-dd"));
|
|
if(!PaidOn.HasValue)
|
|
throw new Exception();
|
|
cmd.Parameters.AddWithValue("@PaidOn", PaidOn.Value.ToString("yyyy-MM-dd"));
|
|
cmd.ExecuteNonQuery();
|
|
return PaymentStatus.SuccessfulPayment;
|
|
}
|
|
internal void Refund()
|
|
{
|
|
/*
|
|
* This function is unused, however, it exists for when refund functionality becomes
|
|
* supported. As for the functionality, this sets the refund amount in the database and
|
|
* zeros it out as if it has been refunded. There is no payment system so changes are
|
|
* heavily simplified compared to real world scenarios.
|
|
*/
|
|
RefundAmount = 0;
|
|
using Database Manager = new(); // Creates a new database connection
|
|
using SQLiteCommand cmd = Manager.con.CreateCommand(); // Creates a new command that will be executed in the database
|
|
string? query = QueryBuilder.UpdateTransaction(Id: Id, Refund: RefundAmount); // Query string with parameters
|
|
|
|
if (query == null)
|
|
{
|
|
throw new Exception();
|
|
}
|
|
|
|
cmd.CommandText = query;
|
|
cmd.Parameters.AddWithValue("@ID", Id);
|
|
cmd.Parameters.AddWithValue("@RefundAmount", RefundAmount);
|
|
cmd.ExecuteNonQuery();
|
|
}
|
|
}
|
|
|
|
internal static class TxFunctions
|
|
{
|
|
/*
|
|
* This class is a set of functions that are not specifically
|
|
* tied to the Transaction class, but are closely related.
|
|
* This class is typically called upon for specific functions
|
|
* or information such as fee multipliers.
|
|
*/
|
|
internal static double ConventionalFee = 1.0;
|
|
internal static double PrepaidFee = 0.75;
|
|
internal static double SixtyDayFee = 0.85;
|
|
internal static double Changed = 1.1;
|
|
internal static double IncentiveFee(DateTime Start, DateTime End)
|
|
{
|
|
/*
|
|
* This returns the incentive fee if the hotel is operating
|
|
* at an occupancy of 60% or less. If so the fee mutltiplier
|
|
* is 80% else 100%.
|
|
*/
|
|
int thirtyDayOcc;
|
|
(thirtyDayOcc, _) = Hotel.AvgOccupancySpan(Start, End);
|
|
if ((double)(thirtyDayOcc / 45.0) <= 0.6)
|
|
{
|
|
return 0.80;
|
|
}
|
|
return 1.0;
|
|
}
|
|
internal static DateTime GetPayByDate(ReservationType Type, DateTime StartDate, DateTime EndDate)
|
|
{
|
|
/*
|
|
* This class reports the date a reservation should be paid on
|
|
* at the latest based on the reservation type.
|
|
*/
|
|
switch (Type)
|
|
{
|
|
case ReservationType.Conventional: return EndDate;
|
|
case ReservationType.Prepaid: return StartDate;
|
|
case ReservationType.Incentive: return EndDate;
|
|
case ReservationType.SixtyDayAdvance: return StartDate.AddDays(-30);
|
|
default: throw new NotImplementedException();
|
|
}
|
|
}
|
|
internal static double CalculateOwed(double Rate, int Days, double Multiplier)
|
|
{
|
|
// Calculates the amount owed rounded to two decimals
|
|
return Math.Round(Rate * Days * Multiplier, 2);
|
|
}
|
|
|
|
|
|
}
|
|
internal enum PaymentStatus // Represents numerical values as words
|
|
{
|
|
SuccessfulPayment,
|
|
AlreadyPaid,
|
|
FailedPayment,
|
|
AmountCannotZero,
|
|
MissingCreditCard
|
|
}
|
|
}
|