private List <FlatRate> GetFlatRates(CPRateRQ oRequest, List <FlatRate> oFlatRates) { List <FlatRate> lstRates = new List <FlatRate>(); try { TimeSpan tsTimeParked = oRequest.ExitDT - oRequest.EntryDT; int nMinutesParked = (int)Math.Ceiling(tsTimeParked.TotalSeconds / 60.0); // Round up to get total minutes or part thereof foreach (var r in oFlatRates) { // Check if there exists Conditions for the Entry Day of the week var conditions = r.Conditions.Where(a => a.DayOfTheWeek == oRequest.EntryDT.DayOfWeek).ToList(); foreach (var c in conditions) { // Go further and figure out if we entered during the entry period and exited during the exit period for the Condition // Determine the Date range for the Entry string strEntryStart = System.String.Format("{0:yyyy-MM-dd} {1}", oRequest.EntryDT, c.EntryStartTime); DateTime dtEntryStart = Convert.ToDateTime(strEntryStart); string strEntryEnd = System.String.Format("{0:yyyy-MM-dd} {1}", dtEntryStart.AddDays(c.EntryEndAddDays), c.EntryEndTime); DateTime dtEntryEnd = Convert.ToDateTime(strEntryEnd); if (dtEntryEnd <= dtEntryStart) { dtEntryEnd = dtEntryEnd.AddDays(1); } // Determine the date range for the Exit string strExitStart = System.String.Format("{0:yyyy-MM-dd} {1}", dtEntryStart.AddDays(c.DaysBetweenEntryExit), c.ExitStartTime); DateTime dtExitStart = Convert.ToDateTime(strExitStart); string strExitEnd = System.String.Format("{0:yyyy-MM-dd} {1}", dtExitStart.AddDays(c.ExitEndAddDays), c.ExitEndTime); DateTime dtExitEnd = Convert.ToDateTime(strExitEnd); if (dtExitEnd <= dtExitStart) { dtExitEnd = dtExitEnd.AddDays(1); } // Put in an extra check to make sure we don't go over the time period - E.g. this would prevent them getting the weekend rate if they stayed for a week int nMaxMinutes = (int)Math.Ceiling((dtExitEnd - dtEntryStart).TotalSeconds / 60.0); if (oRequest.EntryDT >= dtEntryStart && oRequest.EntryDT <= dtEntryEnd && oRequest.ExitDT >= dtExitStart && oRequest.ExitDT <= dtExitEnd && nMinutesParked <= nMaxMinutes) { lstRates.Add(r); break; } } } } catch (Exception) { return(new List <FlatRate>()); } return(lstRates); }
public string GetRate([FromUri] DateTime dtEntry, [FromUri] DateTime dtExit, [FromBody] Rates oRateCard) { CPRateRQ oInput = new CPRateRQ() { EntryDT = dtEntry, ExitDT = dtExit }; string sRate = GetCalculatedRate(oInput, oRateCard); return(sRate); }
public void TestStandardRates() { // Requirement: // 0 - 1 Hours : $5 // 1 - 2 Hours : $10 // 2 - 3 Hours : $15 // 3+ Hours : $20 flat rate for each calendar day of parking var engine = new CarparkRE_Lib.RateEngine(); var ret = engine.LoadRates("CarParkRates.json"); Assert.IsTrue(ret == 0); DateTime dtTest = new DateTime(2021, 4, 15); CPRateRQ rq = new CPRateRQ(); // Standard Rate - 47 Mins rq.EntryDT = dtTest.AddHours(9); // Thursday 9:00 AM rq.ExitDT = dtTest.AddHours(9).AddMinutes(47); // Thursday 9:47 AM var rs = engine.CalculateParkingCharge(rq); Assert.IsTrue(rs.RateName == "Standard Rate"); Assert.IsTrue(rs.TotalPrice == 5); // Standard Rate - 1 Hour 47 Mins rq.EntryDT = dtTest.AddHours(9); // Thursday 9:00 AM rq.ExitDT = dtTest.AddHours(10).AddMinutes(47); // Thursday 10:47 AM rs = engine.CalculateParkingCharge(rq); Assert.IsTrue(rs.RateName == "Standard Rate"); Assert.IsTrue(rs.TotalPrice == 10); // Standard Rate - 2 Hours 47 Mins rq.EntryDT = dtTest.AddHours(9); // Thursday 9:00 AM rq.ExitDT = dtTest.AddHours(11).AddMinutes(47); // Thursday 11:47 AM rs = engine.CalculateParkingCharge(rq); Assert.IsTrue(rs.RateName == "Standard Rate"); Assert.IsTrue(rs.TotalPrice == 15); // Standard Rate - 3 Hours 47 Mins rq.EntryDT = dtTest.AddHours(9); // Thursday 9:00 AM rq.ExitDT = dtTest.AddHours(12).AddMinutes(47); // Thursday 12:47 rs = engine.CalculateParkingCharge(rq); Assert.IsTrue(rs.RateName == "Standard Rate"); Assert.IsTrue(rs.TotalPrice == 20); // Standard Rate - 2 Days 7 Hours 47 Mins - Maximum Rate $20 per day rq.EntryDT = dtTest.AddHours(9); // Thursday 9:00 AM rq.ExitDT = dtTest.AddDays(2).AddHours(16).AddMinutes(47); // Saturday 16:47 (4:47 PM) rs = engine.CalculateParkingCharge(rq); Assert.IsTrue(rs.RateName == "Standard Rate"); Assert.IsTrue(rs.TotalPrice == 60); }
public void APITestCheapestRate() { // Requirements: // The customer should get the cheapest deal based on the rules which apply to the time period var engine = new RateEngineController(); DateTime dtTest = new DateTime(2021, 4, 15); CPRateRQ rq = new CPRateRQ(); // Crossover Case: Qualifies for Standard Rate - 7 Hours 47 Mins ($20) or Early Bird Rate ($13) rq.EntryDT = dtTest.AddHours(9); // Thursday 9:00 AM rq.ExitDT = dtTest.AddHours(16).AddMinutes(47); // Thursday 16:47 (4:47 PM) var rs = JsonConvert.DeserializeObject <CPRateRS>(engine.GetRate(rq.EntryDT, rq.ExitDT, GetRates())); Assert.IsTrue(rs.RateName == "Early Bird"); Assert.IsTrue(rs.TotalPrice == 13); }
public void APITestStandardRate() { var engine = new RateEngineController(); DateTime dtTest = new DateTime(2021, 4, 15); CPRateRQ rq = new CPRateRQ(); // Standard Rate - 47 Mins rq.EntryDT = dtTest.AddHours(9); // Thursday 9:00 AM rq.ExitDT = dtTest.AddHours(9).AddMinutes(47); // Thursday 9:47 AM var rs = JsonConvert.DeserializeObject <CPRateRS>(engine.GetRate(rq.EntryDT, rq.ExitDT, GetRates())); Assert.IsTrue(rs.RateName == "Standard Rate"); Assert.IsTrue(rs.TotalPrice == 5); // Standard Rate - 1 Hour 47 Mins rq.EntryDT = dtTest.AddHours(9); // Thursday 9:00 AM rq.ExitDT = dtTest.AddHours(10).AddMinutes(47); // Thursday 10:47 AM rs = JsonConvert.DeserializeObject <CPRateRS>(engine.GetRate(rq.EntryDT, rq.ExitDT, GetRates())); Assert.IsTrue(rs.RateName == "Standard Rate"); Assert.IsTrue(rs.TotalPrice == 10); // Standard Rate - 2 Hours 47 Mins rq.EntryDT = dtTest.AddHours(9); // Thursday 9:00 AM rq.ExitDT = dtTest.AddHours(11).AddMinutes(47); // Thursday 11:47 AM rs = JsonConvert.DeserializeObject <CPRateRS>(engine.GetRate(rq.EntryDT, rq.ExitDT, GetRates())); Assert.IsTrue(rs.RateName == "Standard Rate"); Assert.IsTrue(rs.TotalPrice == 15); // Standard Rate - 3 Hours 47 Mins rq.EntryDT = dtTest.AddHours(9); // Thursday 9:00 AM rq.ExitDT = dtTest.AddHours(12).AddMinutes(47); // Thursday 12:47 rs = JsonConvert.DeserializeObject <CPRateRS>(engine.GetRate(rq.EntryDT, rq.ExitDT, GetRates())); Assert.IsTrue(rs.RateName == "Standard Rate"); Assert.IsTrue(rs.TotalPrice == 20); // Standard Rate - 2 Days 7 Hours 47 Mins - Maximum Rate $20 per day rq.EntryDT = dtTest.AddHours(9); // Thursday 9:00 AM rq.ExitDT = dtTest.AddDays(2).AddHours(16).AddMinutes(47); // Saturday 16:47 (4:47 PM) rs = JsonConvert.DeserializeObject <CPRateRS>(engine.GetRate(rq.EntryDT, rq.ExitDT, GetRates())); Assert.IsTrue(rs.RateName == "Standard Rate"); Assert.IsTrue(rs.TotalPrice == 60); }
/// <summary> /// Determines the Rate and Amount to charge the customer for Parking /// </summary> /// <param name="oRequest">Is an Object from the CarparkRE Library that contains the EntryDateTime and ExitDateTime of the customers parking session</param> /// <returns></returns> public CPRateRS CalculateParkingCharge(CPRateRQ oRequest) { CPRateRS oRet = new CPRateRS(); try { // Make sure we have some rates loaded if (_mRates.RateCount() == 0) { return(oRet); } // Begin with the Standard Rate as the parking charge by default oRet.RateName = _mRates.StandardRates.Name; oRet.TotalPrice = GetStandardRateAmount(oRequest, GetStandardRates()); // Find any flat rates that apply List <FlatRate> lstFlatRates = GetFlatRates(oRequest, GetFlatRates()); // Select the cheapest rate for the customer, default is the Standard Rate foreach (var r in lstFlatRates) { if (r.Amount < oRet.TotalPrice) { // Overwrite the default Standard Rate with the Flat Rate instead oRet.RateName = r.Name; oRet.TotalPrice = r.Amount; } } } catch (Exception e) { // Record any errors in the return object oRet = new CPRateRS() { ErrorHResult = e.HResult, ErrorMsg = e.ToString() }; } return(oRet); }
/// <summary> /// Figures out the Standard Rates to apply for the given carpark session /// </summary> /// <param name="oRequest">Is an Object from the CarparkRE Library that contains the EntryDateTime and ExitDateTime of the customers parking session</param> /// <param name="oStdRates">Standard Rates as loded from the LoadRates function</param> /// <returns></returns> private decimal GetStandardRateAmount(CPRateRQ oRequest, StandardRate oStdRates) { decimal dAmount = 0; try { // Determine the total hours parked ot match with our Standard Rates TimeSpan tsTimeParked = oRequest.ExitDT - oRequest.EntryDT; int nHoursParked = (int)Math.Ceiling(tsTimeParked.TotalSeconds / 3600.0); // Round up to get total hours or part thereof TimeLimit oTimeSelected = null; // Check if we need to apply the max standard rate if (nHoursParked > oStdRates.MaxAmountHours) { // Check if they get the max standard rate multiple times - E.g. been there for multiple calendar days while (nHoursParked >= oStdRates.MaxAmountHours) { dAmount += oStdRates.MaxAmount; nHoursParked -= oStdRates.MaxAmountHours; } // Make sure we add on the remainder from the Standard Rate. E.g. Charged max amount for 2 days and then for 2 hours on the last day if (nHoursParked > 0) { oTimeSelected = oStdRates.TimeLimits.FirstOrDefault(a => nHoursParked > a.StartHours && nHoursParked <= a.EndHours); dAmount += oTimeSelected != null ? oTimeSelected.Amount : 0; } } else { // Hours in the carpark are less than the maximum hours before we click over for a second flat rate, so find the appopriate one oTimeSelected = oStdRates.TimeLimits.FirstOrDefault(a => nHoursParked > a.StartHours && nHoursParked <= a.EndHours); dAmount = oTimeSelected != null ? oTimeSelected.Amount : 0; } } catch (Exception) { return(dAmount); } return(dAmount); }
public void TestCheapestRate() { // Requirements: // The customer should get the cheapest deal based on the rules which apply to the time period var engine = new CarparkRE_Lib.RateEngine(); var ret = engine.LoadRates("CarParkRates.json"); Assert.IsTrue(ret == 0); DateTime dtTest = new DateTime(2021, 4, 15); CPRateRQ rq = new CPRateRQ(); // Crossover Case: Qualifies for Standard Rate - 7 Hours 47 Mins ($20) or Early Bird Rate ($13) rq.EntryDT = dtTest.AddHours(9); // Thursday 9:00 AM rq.ExitDT = dtTest.AddHours(16).AddMinutes(47); // Thursday 16:47 (4:47 PM) var rs = engine.CalculateParkingCharge(rq); Assert.IsTrue(rs.RateName == "Early Bird"); Assert.IsTrue(rs.TotalPrice == 13); }
public void APITestEarlyBird() { // Requirements: // Name: Early Bird // Type: Flat Rate // Total Price: $13.00 // Entry Condition: Enter between 6:00 AM to 9:00 AM // Exit Condition: Exit between 3:30 PM to 11:30 PM var engine = new RateEngineController(); DateTime dtTest = new DateTime(2021, 4, 15); CPRateRQ rq = new CPRateRQ(); rq.EntryDT = dtTest.AddHours(6).AddMinutes(30); // Thursday 06:30 AM rq.ExitDT = dtTest.AddHours(16).AddMinutes(30); // Thursday 16:30 (4:30 PM) var rs = JsonConvert.DeserializeObject <CPRateRS>(engine.GetRate(rq.EntryDT, rq.ExitDT, GetRates())); Assert.IsTrue(rs.RateName == "Early Bird"); Assert.IsTrue(rs.TotalPrice == 13); }
public void APITestWeekendRate() { // Requirements: // Name: Weekend Rate // Type: Flat Rate // Total Price: $10.00 // Entry Condition: Enter anytime past midnight on Friday // Exit Condition: Exit any time before midnight on Sunday var engine = new RateEngineController(); DateTime dtTest = new DateTime(2021, 4, 17); CPRateRQ rq = new CPRateRQ(); // Weekend Rate rq.EntryDT = dtTest.AddMinutes(12); // Saturday 00:12 AM rq.ExitDT = dtTest.AddDays(1).AddHours(12).AddMinutes(47); // Sunday 12:47 PM var rs = JsonConvert.DeserializeObject <CPRateRS>(engine.GetRate(rq.EntryDT, rq.ExitDT, GetRates())); Assert.IsTrue(rs.RateName == "Weekend Rate"); Assert.IsTrue(rs.TotalPrice == 10); }