public async Task subsequent_requests_offer_only_prices_for_new_dates()
        {
            // Given
            var id          = ReservationId.New;
            var reservation = new Reservation(id);

            var arrivalDate             = new DateTime(2020, 02, 01);
            var date2                   = new DateTime(2020, 02, 02);
            var departureDate           = new DateTime(2020, 02, 03);
            var irrelevantOfferedPrice1 = Money.Euro(101);
            var irrelevantOfferedPrice2 = Money.Euro(101);

            reservation.Apply(
                new PriceOffered(arrivalDate, irrelevantOfferedPrice1, DateTime.UtcNow.AddMinutes(30)));

            var mockPriceEngine = new Mock <IPricingEngine>();

            SetupPriceEngineReturnsPriceForDate(mockPriceEngine, arrivalDate, irrelevantOfferedPrice1);
            SetupPriceEngineReturnsPriceForDate(mockPriceEngine, date2, irrelevantOfferedPrice2);

            var handler = new CreateOfferHandler(mockPriceEngine.Object);

            // When
            var result = await handler.ExecuteCommandAsync(
                reservation,
                new CreateOffer(id, arrivalDate, departureDate),
                CancellationToken.None);

            // Then
            Assert.True(result.IsSuccess);

            var priceOffered = (PriceOffered)reservation.UncommittedEvents.Single().AggregateEvent;

            Assert.Equal(date2, priceOffered.Date);
        }
        public async Task if_price_not_available_then_does_not_record_a_price_offer()
        {
            // Given
            var id          = ReservationId.New;
            var reservation = new Reservation(id);

            var arrivalDate   = new DateTime(2020, 02, 01);
            var departureDate = new DateTime(2020, 02, 02);

            var mockPriceEngine = new Mock <IPricingEngine>();

            SetupPriceEngineReturnsPriceForDate(mockPriceEngine, arrivalDate, Option <Money> .None);

            var handler = new CreateOfferHandler(mockPriceEngine.Object);

            // When
            var result = await handler.ExecuteCommandAsync(
                reservation,
                new CreateOffer(id, arrivalDate, departureDate),
                CancellationToken.None);

            // Then
            Assert.True(result.IsSuccess);
            Assert.Empty(reservation.UncommittedEvents);
        }
        public void AddsOfferToRepository_RaisesIntegrationEvent()
        {
            var repository = new Mock <IOfferRepository>(MockBehavior.Strict);

            repository.Setup(r => r.AddAsync(It.Is <Domain.Offer>(p => ValidateEquality(p)))).Returns(Task.CompletedTask).Verifiable();
            repository.Setup(r => r.SaveChanges()).Returns(Task.CompletedTask).Verifiable();

            var busPublisher = new Mock <IBusPublisher>(MockBehavior.Strict);

            busPublisher.Setup(p => p.Publish <IOfferCreated>(It.Is <IOfferCreated>(e => ValidateEquality(e)))).Returns(Task.CompletedTask).Verifiable();

            var posVerifier = new Mock <IPointOfSaleVerifier>(MockBehavior.Strict);

            posVerifier.Setup(v => v.AssertExists(PointOfSaleId)).Returns(Task.CompletedTask).Verifiable();

            var productVerifier = new Mock <IProductVerifier>(MockBehavior.Strict);

            productVerifier.Setup(v => v.AssertExists(ProductId)).Returns(Task.CompletedTask).Verifiable();

            var stockItemVerifier = new Mock <IStockItemVerifier>(MockBehavior.Strict);

            stockItemVerifier.Setup(v => v.AssertExists(StockItemId)).Returns(Task.CompletedTask).Verifiable();

            var handler = new CreateOfferHandler(repository.Object, busPublisher.Object, posVerifier.Object, productVerifier.Object, stockItemVerifier.Object);
            var result  = handler.HandleAsync(Cmd, new Mock <ICorrelationContext>().Object).GetAwaiter().GetResult();

            Assert.IsTrue(result.Successful);
            repository.Verify();
            busPublisher.Verify();
            posVerifier.Verify();
            productVerifier.Verify();
            stockItemVerifier.Verify();
        }
        public async Task creates_offer_for_every_day_of_staying_at_hotel()
        {
            // Given
            var id          = ReservationId.New;
            var reservation = new Reservation(id);

            var arrivalDate   = new DateTime(2020, 02, 01);
            var date2         = new DateTime(2020, 02, 02);
            var departureDate = new DateTime(2020, 02, 03);

            var price1           = Money.Euro(101);
            var price2           = Money.Euro(102);
            var irrelevantPrice3 = Money.Euro(103);

            var mockPriceEngine = new Mock <IPricingEngine>();

            SetupPriceEngineReturnsPriceForDate(mockPriceEngine, arrivalDate, price1);
            SetupPriceEngineReturnsPriceForDate(mockPriceEngine, date2, price2);
            SetupPriceEngineReturnsPriceForDate(mockPriceEngine, departureDate, irrelevantPrice3);

            var offersShouldExpireOn = DateTime.UtcNow.AddMinutes(30);

            var handler = new CreateOfferHandler(mockPriceEngine.Object);

            // When
            var result = await handler.ExecuteCommandAsync(
                reservation,
                new CreateOffer(id, arrivalDate, departureDate),
                CancellationToken.None);

            // Then
            Assert.True(result.IsSuccess);

            var uncommittedEvents = reservation.UncommittedEvents.ToArray();

            Assert.Equal(2, uncommittedEvents.Length);

            var firstPriceOffered = (PriceOffered)uncommittedEvents[0].AggregateEvent;

            Assert.Equal(arrivalDate, firstPriceOffered.Date);
            Assert.Equal(price1, firstPriceOffered.Price);
            Assert.InRange(firstPriceOffered.Expires, offersShouldExpireOn, offersShouldExpireOn.AddSeconds(1));

            var secondPriceOffered = (PriceOffered)uncommittedEvents[1].AggregateEvent;

            Assert.Equal(date2, secondPriceOffered.Date);
            Assert.Equal(price2, secondPriceOffered.Price);
            Assert.InRange(secondPriceOffered.Expires, offersShouldExpireOn, offersShouldExpireOn.AddSeconds(1));
        }
        public async Task if_old_price_offer_has_expired_then_produces_a_new_price_offer()
        {
            // Given
            var id          = ReservationId.New;
            var reservation = new Reservation(id);

            var arrivalDate   = new DateTime(2020, 02, 01);
            var departureDate = new DateTime(2020, 02, 03);
            var offeredPrice  = Money.Euro(101);
            var newPrice      = Money.Euro(102);

            reservation.Apply(new PriceOffered(arrivalDate, offeredPrice, DateTime.UtcNow.AddSeconds(-1)));

            var mockPriceEngine = new Mock <IPricingEngine>();

            SetupPriceEngineReturnsPriceForDate(mockPriceEngine, arrivalDate, newPrice);

            var newOfferShouldExpireOn = DateTime.UtcNow.AddMinutes(30);

            var handler = new CreateOfferHandler(mockPriceEngine.Object);

            // When
            var result = await handler.ExecuteCommandAsync(
                reservation,
                new CreateOffer(id, arrivalDate, departureDate),
                CancellationToken.None);

            // Then
            Assert.True(result.IsSuccess);

            var uncommittedEvents = reservation.UncommittedEvents.ToArray();

            var newPriceOffered = (PriceOffered)uncommittedEvents.Single().AggregateEvent;

            Assert.Equal(arrivalDate, newPriceOffered.Date);
            Assert.Equal(newPrice, newPriceOffered.Price);

            Assert.InRange(newPriceOffered.Expires, newOfferShouldExpireOn, newOfferShouldExpireOn.AddSeconds(1));
        }