private ActionResult CompleteRegistrationWithThirdPartyProcessorPayment(AssignRegistrantDetails command, PricedOrder order, int orderVersion)
        {
            var paymentCommand = CreatePaymentCommand(order);

            this.commandBus.Send(new ICommand[] { command, paymentCommand });

            var paymentAcceptedUrl = this.Url.Action("ThankYou", new { conferenceCode = this.ConferenceAlias.Code, order.OrderId });
            var paymentRejectedUrl = this.Url.Action("SpecifyRegistrantAndPaymentDetails", new { conferenceCode = this.ConferenceAlias.Code, orderId = order.OrderId, orderVersion });

            return RedirectToAction(
                "ThirdPartyProcessorPayment",
                "Payment",
                new
                {
                    conferenceCode = this.ConferenceAlias.Code,
                    paymentId = paymentCommand.PaymentId,
                    paymentAcceptedUrl,
                    paymentRejectedUrl
                });
        }
        private ActionResult CompleteRegistrationWithoutPayment(AssignRegistrantDetails command, Guid orderId)
        {
            var confirmationCommand = new ConfirmOrder { OrderId = orderId };

            this.commandBus.Send(new ICommand[] { command, confirmationCommand });

            return RedirectToAction("ThankYou", new { conferenceCode = this.ConferenceAlias.Code, orderId });
        }
        public ActionResult SpecifyRegistrantAndPaymentDetails(AssignRegistrantDetails command, string paymentType, int orderVersion)
        {
            var orderId = command.OrderId;

            if (!ModelState.IsValid)
            {
                return SpecifyRegistrantAndPaymentDetails(orderId, orderVersion);
            }

            var order = this.orderDao.FindDraftOrder(orderId);

            // TODO check conference and order exist.
            // TODO validate that order belongs to the user.

            if (order == null)
            {
                throw new ArgumentException();
            }

            if (order.ReservationExpirationDate.HasValue && order.ReservationExpirationDate < DateTime.UtcNow)
            {
                return RedirectToAction("ShowExpiredOrder", new { conferenceCode = this.ConferenceAlias.Code, orderId = orderId });
            }

            var pricedOrder = this.orderDao.FindPricedOrder(orderId);
            if (pricedOrder.IsFreeOfCharge)
            {
                return CompleteRegistrationWithoutPayment(command, orderId);
            }

            switch (paymentType)
            {
                case ThirdPartyProcessorPayment:

                    return CompleteRegistrationWithThirdPartyProcessorPayment(command, pricedOrder, orderVersion);

                case InvoicePayment:
                    break;

                default:
                    break;
            }

            throw new InvalidOperationException();
        }
        public void when_specifying_registrant_and_credit_card_payment_details_for_a_non_yet_updated_order_then_shows_wait_page()
        {
            var orderId = Guid.NewGuid();
            var orderVersion = 10;
            var command = new AssignRegistrantDetails
            {
                OrderId = orderId,
                Email = "*****@*****.**",
                FirstName = "First Name",
                LastName = "Last Name",
            };
            Guid paymentId = Guid.Empty;

            var seatTypeId = Guid.NewGuid();

            Mock.Get(this.orderDao)
                .Setup(r => r.FindDraftOrder(orderId))
                .Returns(
                    new DraftOrder(orderId, conferenceAlias.Id, DraftOrder.States.Confirmed, orderVersion)
                    {
                        Lines = { new DraftOrderItem(seatTypeId, 10) { ReservedSeats = 5 } }
                    });
            Mock.Get<IOrderDao>(this.orderDao)
                .Setup(d => d.FindPricedOrder(orderId))
                .Returns(new PricedOrder { OrderId = orderId, Total = 100, OrderVersion = orderVersion + 1 });
            var result = (ViewResult)this.sut.SpecifyRegistrantAndPaymentDetails(command, RegistrationController.ThirdPartyProcessorPayment, orderVersion).Result;

            Assert.Equal("ReservationUnknown", result.ViewName);
        }
        public void when_specifying_registrant_and_credit_card_payment_details_for_a_valid_registration_then_sends_commands_and_redirects_to_payment_action()
        {
            var orderId = Guid.NewGuid();
            var command = new AssignRegistrantDetails
            {
                OrderId = orderId,
                Email = "*****@*****.**",
                FirstName = "First Name",
                LastName = "Last Name",
            };
            InitiateThirdPartyProcessorPayment paymentCommand = null;

            // Arrange
            var seatId = Guid.NewGuid();

            var order = new DraftOrder(orderId, conferenceAlias.Id, DraftOrder.States.ReservationCompleted, 10);
            order.Lines.Add(new DraftOrderItem(seatId, 5) { ReservedSeats = 5 });
            Mock.Get<IOrderDao>(this.orderDao)
                .Setup(d => d.FindDraftOrder(orderId))
                .Returns(order);
            Mock.Get<IOrderDao>(this.orderDao)
                .Setup(d => d.FindPricedOrder(orderId))
                .Returns(new PricedOrder { OrderId = orderId, Total = 100, OrderVersion = 10});

            Mock.Get<ICommandBus>(this.bus)
                .Setup(b => b.Send(It.IsAny<Envelope<ICommand>>()))
                .Callback<Envelope<ICommand>>(
                    es => { if (es.Body is InitiateThirdPartyProcessorPayment) paymentCommand = (InitiateThirdPartyProcessorPayment)es.Body; });

            this.routes.MapRoute("ThankYou", "thankyou", new { controller = "Registration", action = "ThankYou" });
            this.routes.MapRoute("SpecifyRegistrantAndPaymentDetails", "checkout", new { controller = "Registration", action = "SpecifyRegistrantAndPaymentDetails" });

            // Act
            var result =
                (RedirectToRouteResult)this.sut.SpecifyRegistrantAndPaymentDetails(command, RegistrationController.ThirdPartyProcessorPayment, 0).Result;

            // Assert
            Mock.Get<ICommandBus>(this.bus)
                .Verify(b => b.Send(It.Is<Envelope<ICommand>>(es => es.Body == command)), Times.Once());
            
            Assert.NotNull(paymentCommand);
            Assert.Equal(conferenceAlias.Id, paymentCommand.ConferenceId);
            Assert.Equal(orderId, paymentCommand.PaymentSourceId);
            Assert.InRange(paymentCommand.TotalAmount, 99.9m, 100.1m);

            Assert.Equal("Payment", result.RouteValues["controller"]);
            Assert.Equal("ThirdPartyProcessorPayment", result.RouteValues["action"]);
            Assert.Equal(this.conferenceAlias.Code, result.RouteValues["conferenceCode"]);
            Assert.Equal(paymentCommand.PaymentId, result.RouteValues["paymentId"]);
            Assert.True(((string)result.RouteValues["paymentAcceptedUrl"]).StartsWith("/thankyou"));
            Assert.True(((string)result.RouteValues["paymentRejectedUrl"]).StartsWith("/checkout"));
        }
        public Task<ActionResult> SpecifyRegistrantAndPaymentDetails(AssignRegistrantDetails command, string paymentType, int orderVersion)
        {
            var orderId = command.OrderId;

            if (!ModelState.IsValid)
            {
                return SpecifyRegistrantAndPaymentDetails(orderId, orderVersion);
            }

            this.commandBus.Send(command);

            return this.StartPayment(orderId, paymentType, orderVersion);
        }
        public void when_specifying_registrant_and_credit_card_payment_details_for_a_valid_registration_then_sends_commands_and_redirects_to_payment_action()
        {
            var orderId = Guid.NewGuid();
            var command = new AssignRegistrantDetails
            {
                OrderId = orderId,
                Email = "*****@*****.**",
                FirstName = "First Name",
                LastName = "Last Name",
            };
            Guid paymentId = Guid.Empty;

            // Arrange
            var seatId = Guid.NewGuid();

            var order = new DraftOrder(orderId, conferenceAlias.Id, DraftOrder.States.ReservationCompleted);
            order.Lines.Add(new DraftOrderItem(seatId, 5) { ReservedSeats = 5 });
            Mock.Get<IOrderDao>(this.orderDao)
                .Setup(d => d.FindDraftOrder(orderId))
                .Returns(order);
            Mock.Get<IOrderDao>(this.orderDao)
                .Setup(d => d.FindPricedOrder(orderId))
                .Returns(new PricedOrder { OrderId = orderId, Total = 100 });

            Mock.Get<ICommandBus>(this.bus)
                .Setup(b => b.Send(It.IsAny<IEnumerable<Envelope<ICommand>>>()))
                .Callback<IEnumerable<Envelope<ICommand>>>(
                    es => { paymentId = (es.Select(e => e.Body).OfType<InitiateThirdPartyProcessorPayment>().First()).PaymentId; });

            this.routes.MapRoute("ThankYou", "thankyou", new { controller = "Registration", action = "ThankYou" });
            this.routes.MapRoute("SpecifyRegistrantAndPaymentDetails", "checkout", new { controller = "Registration", action = "SpecifyRegistrantAndPaymentDetails" });

            // Act
            var result =
                (RedirectToRouteResult)this.sut.SpecifyRegistrantAndPaymentDetails(command, RegistrationController.ThirdPartyProcessorPayment, 0);

            // Assert
            Mock.Get<ICommandBus>(this.bus)
                .Verify(
                    b =>
                        b.Send(
                            It.Is<IEnumerable<Envelope<ICommand>>>(es =>
                                es.Select(e => e.Body).Any(c => c == command)
                                && es.Select(e => e.Body).OfType<InitiateThirdPartyProcessorPayment>()
                                     .Any(c =>
                                         c.ConferenceId == conferenceAlias.Id
                                         && c.PaymentSourceId == orderId
                                         && Math.Abs(c.TotalAmount - 100) < 0.01m)
                                && es.Select(e => e.Body).Contains(command))),
                    Times.Once());

            Assert.Equal("Payment", result.RouteValues["controller"]);
            Assert.Equal("ThirdPartyProcessorPayment", result.RouteValues["action"]);
            Assert.Equal(this.conferenceAlias.Code, result.RouteValues["conferenceCode"]);
            Assert.Equal(paymentId, result.RouteValues["paymentId"]);
            Assert.True(((string)result.RouteValues["paymentAcceptedUrl"]).StartsWith("/thankyou"));
            Assert.True(((string)result.RouteValues["paymentRejectedUrl"]).StartsWith("/checkout"));
        }