/// <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);
        }
Esempio n. 7
0
        /// <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);
        }
Esempio n. 8
0
        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"));
        }
Esempio n. 9
0
        /// <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;
        }