/// <summary> /// Calculate the total price for the specified flights and passengers. /// </summary> /// <param name="flights">The SelectedFlights object containing flight and passenger information.</param> /// <returns>An asynchronous task for calculating the total price.</returns> public async Task <decimal> CalculateTotalPriceAsync(SelectedFlights flights) { decimal firstClassMultiplier = 5; decimal childMultiplier = 0.6M; decimal actualCost = 0; decimal outboundBaseCost = await CalculateBasePriceAsync(flights.Outbound); // Inbound flight base cost is calculated if return flight or 0 is flight is one-way. decimal inboundBaseCost = flights.IsReturn ? await CalculateBasePriceAsync(flights.Inbound) : 0; decimal outboundTotalCost = (flights.NumberAdults * outboundBaseCost) + (flights.NumberChildren * childMultiplier * outboundBaseCost); decimal inboundTotalCost = (flights.NumberAdults * inboundBaseCost) + (flights.NumberChildren * childMultiplier * inboundBaseCost); actualCost = outboundTotalCost + inboundTotalCost; if (flights.TravelClass == Enums.TravelClass.First) { actualCost *= firstClassMultiplier; } flights.Price = actualCost; return(actualCost); }
/// <summary> /// Convert a Flight object to a PricedFlight object. /// </summary> /// <param name="flight">The flight to convert and price.</param> /// <param name="searchData">The FlightSearchDataModel to be used to help calculate the price of the flight.</param> /// <param name="calculator">The IFlightPriceCalculator to be used to help calculate the price of the flight.</param> /// <returns>An asynchronous task for pricing the flight.</returns> public static async Task <PricedFlight> PriceFlightAsync(this Flight flight, FlightSearchDataModel searchData, IFlightPriceCalculator calculator) { // Create PricedFlight object. var output = new PricedFlight { Flight = flight }; // Put contents of flight and search data into SelectedFlights object // so total price can be calculated. var totalFlight = new SelectedFlights { Outbound = flight, Inbound = null, NumberAdults = searchData.NumberAdults, NumberChildren = searchData.NumberChildren, TravelClass = searchData.TravelClass }; decimal price = await calculator.CalculateTotalPriceAsync(totalFlight); output.TotalPrice = price; return(output); }
public async void CalculateTotalPriceAsync_CalculatesCorrectTotalPrice(TravelClass travelClass, int numAdults, int numChildren, decimal expectedPrice) { Mock <FlightPriceCalculator> mock = new Mock <FlightPriceCalculator>(); mock.SetupSequence(x => x.CalculateBasePriceAsync(It.IsAny <Flight>())) .ReturnsAsync(100M) .ReturnsAsync(150M); var calculator = mock.Object; SelectedFlights selectedFlights = new SelectedFlights() { Outbound = new Flight(), Inbound = new Flight(), TravelClass = travelClass, NumberAdults = numAdults, NumberChildren = numChildren }; decimal actualPrice = await calculator.CalculateTotalPriceAsync(selectedFlights); // Check expected and actual prices match. Assert.Equal(expectedPrice, actualPrice); // Check that TotalPrice property is set in selectedFlights Assert.True(selectedFlights.Price == expectedPrice); }
/// <summary> /// Make a booking and take payment from a user. /// </summary> /// <param name="user">The user that is making the booking.</param> /// <param name="selectedFlights">The flight(s) the user is booking.</param> /// <param name="paymentInfo">The user's card details to pay for the flights.</param> /// <returns>An asynchronous task of MethodResult indicating whether the operation was successful or not.</returns> public async Task <MethodResult> MakeBookingAsync(User user, SelectedFlights selectedFlights, PaymentInfo paymentInfo) { decimal price = selectedFlights.Price; var paymentResult = await _paymentManager.TakePaymentAsync(paymentInfo, price); if (paymentResult.Succeeded == false) { return(MethodResult.Failed(paymentResult.Errors.ToArray())); } // Payment succeeded - create booking. Booking newBooking = new Booking { Last4CardDigits = paymentInfo.CardNumber.Substring(11, 4), CardType = await _paymentManager.GetCardIssuerAsync(paymentInfo.CardNumber), DateTimeCreated = DateTime.Now, FlightsDetails = selectedFlights }; // Generate the booking reference. await GenerateBookingReferenceAsync(newBooking); // Crate booking in database. await _dataAccess.CreateBookingAsync(newBooking, user); // Send confirmation email. await SendBookingConfirmationAsync(user, newBooking); return(MethodResult.Success); }
/// <summary> /// Convert this SelectedFlights object to a SelectedFlightsModel. /// </summary> /// <param name="selectedFlights">The SelectedFlights to convert.</param> /// <param name="calculator">The IFlightPriceCalculator to use to calculate flight prices.</param> public static async Task <SelectedFlightsModel> ToSelectedFlightsModel(this SelectedFlights selectedFlights, IFlightPriceCalculator calculator) { // Populate model with number of passengers and travel class. FlightSearchDataModel searchData = new FlightSearchDataModel { NumberAdults = selectedFlights.NumberAdults, NumberChildren = selectedFlights.NumberChildren, TravelClass = selectedFlights.TravelClass }; SelectedFlightsModel output = new SelectedFlightsModel { Outbound = await selectedFlights.Outbound.PriceFlightAsync(searchData, calculator), Inbound = selectedFlights.Inbound is null ? null : await selectedFlights.Inbound.PriceFlightAsync(searchData, calculator), NumberAdults = selectedFlights.NumberAdults, NumberChildren = selectedFlights.NumberChildren, TravelClass = selectedFlights.TravelClass }; output.TotalPrice = output.Outbound.TotalPrice; if (output.IsReturn) { output.TotalPrice += output.Inbound.TotalPrice; } return(output); } }
/// <summary> /// Convert this SelectedFlightsModel to a SelectedFlights object. /// </summary> /// <param name="model">The SelectedFlightsModel to convert.</param> public static SelectedFlights ToSelectedFlights(this SelectedFlightsModel model) { var output = new SelectedFlights { Outbound = model.Outbound.Flight, NumberAdults = model.NumberAdults, NumberChildren = model.NumberChildren, TravelClass = model.TravelClass, Price = model.TotalPrice }; if (model.IsReturn) { output.Inbound = model.Inbound.Flight; } return(output); }
/// <summary> /// Try to parse inbound and outbound flights Ids given as strings /// populating a SelectedFlights object with those flights if successful. /// </summary> /// <param name="outboundId">The outbound flight Id.</param> /// <param name="inboundId">The inbound flight Id.</param> /// <param name="selectedFlights">A selected flights object containing the flights with the Ids given.</param> /// <returns>True if the Ids were parsed correctly, false otherwise.</returns> private bool TryParseFlightIds(string outboundId, string inboundId, out SelectedFlights selectedFlights) { selectedFlights = null; if (outboundId is null) { // No oubound flight Id. return(false); } int selectedOutboundId = int.Parse(outboundId); int?selectedInboundId = null; if (inboundId != null) { // Return flight is selected. selectedInboundId = int.Parse(inboundId); } // Find flight with given outbound Id. Task <Flight> outboundTask = Task.Run(async() => await _dataAccess.FindFlightByIdAsync(selectedOutboundId)); Flight outbound = outboundTask.Result; Flight inbound = null; if (selectedInboundId.HasValue) { // Find flight with inbound Id if flight is a return flight. Task <Flight> inboundTask = Task.Run(async() => await _dataAccess.FindFlightByIdAsync(selectedInboundId.Value)); inbound = inboundTask.Result; } // Populate selected flights object. selectedFlights = new SelectedFlights { Outbound = outbound, Inbound = inbound }; return(true); }
public async Task <ActionResult> Payment(PaymentDataModel paymentData) { // Populate paymentData model with SelectedFlightsModel data. var selectedFlightsModel = (SelectedFlightsModel)Session["selectedFlightsModel"]; paymentData.SelectedFlights = selectedFlightsModel; if (!ModelState.IsValid) { return(View(paymentData)); } User user = await _dataAccess.FindByNameAsync(User.Identity.Name); SelectedFlights selectedFlights = paymentData.SelectedFlights.ToSelectedFlights(); PaymentInfo paymentInfo = paymentData.ToPaymentInfo(); // Make booking. MethodResult result = await _bookingManager.MakeBookingAsync(user, selectedFlights, paymentInfo); // If booking did not succeed. if (result.Succeeded == false) { // Add errors to model. foreach (var error in result.Errors) { ModelState.AddModelError("", error); } return(View(paymentData)); } // Booking was successful. // Add details to session data. Session.Add("bookingInformation", paymentData); return(RedirectToAction("Confirmation")); }
/// <summary> /// Calculate and set the price property of the SelectedFlights object /// using the IFlightPriceCalculator. /// </summary> /// <param name="selectedFlights">The SelectedFlights object to calculate the price of.</param> /// <returns>An asynchronous task for calculating the flights' price.</returns> private async Task CalculatePriceAsync(SelectedFlights selectedFlights) { decimal price = await _calculator.CalculateTotalPriceAsync(selectedFlights); selectedFlights.Price = price; }