Ejemplo n.º 1
0
            public void when_recalculated_then_replaces_line()
            {
                this.sut.Handle(new OrderTotalsCalculated
                {
                    SourceId = orderId,
                    Lines    = new[]
                    {
                        new SeatOrderLine
                        {
                            LineTotal = 20,
                            SeatType  = this.seatCreatedEvents[1].SourceId,
                            Quantity  = 2,
                            UnitPrice = 10
                        },
                    },
                    Total   = 20,
                    Version = 8,
                });

                this.dto = this.dao.FindPricedOrder(orderId);

                Assert.Equal(1, dto.Lines.Count);
                Assert.Equal(20, dto.Lines[0].LineTotal);
                Assert.Equal(2, dto.Lines[0].Quantity);
                Assert.Equal(10, dto.Lines[0].UnitPrice);
                Assert.Equal(20, dto.Total);
                Assert.Contains("Precon", dto.Lines.Select(x => x.Description));
                Assert.Equal(8, dto.OrderVersion);
            }
        private static bool WasNotAlreadyHandled(PricedOrder pricedOrder, int eventVersion)
        {
            // This assumes that events will be handled in order, but we might get the same message more than once.
            if (eventVersion > pricedOrder.OrderVersion)
            {
                return(true);
            }
            else if (eventVersion == pricedOrder.OrderVersion)
            {
                Trace.TraceWarning(
                    "Ignoring duplicate priced order update message with version {1} for order id {0}",
                    pricedOrder.OrderId,
                    eventVersion);
                return(false);
            }
            else
            {
                throw new InvalidOperationException(
                          string.Format(
                              @"An older order update message was received with with version {1} for order id {0}, last known version {2}.
This read model generator has an expectation that the EventBus will deliver messages for the same source in order.",
                              pricedOrder.OrderId,
                              eventVersion,
                              pricedOrder.OrderVersion));
            }
        }
 private static bool WasNotAlreadyHandled(PricedOrder pricedOrder, int eventVersion)
 {
     // This assumes that events will be handled in order, but we might get the same message more than once.
     if (eventVersion > pricedOrder.OrderVersion)
     {
         return(true);
     }
     else if (eventVersion == pricedOrder.OrderVersion)
     {
         /*Trace.TraceWarning(
          *  "Ignoring duplicate priced order update message with version {1} for order id {0}",
          *  pricedOrder.OrderId,
          *  eventVersion);*/
         return(false);
     }
     else
     {
         /*Trace.TraceWarning(
          *  @"Ignoring an older order update message was received with with version {1} for order id {0}, last known version {2}.
          * This read model generator has an expectation that the EventBus will deliver messages for the same source in order. Nevertheless, this warning can be expected in a migration scenario.",
          *  pricedOrder.OrderId,
          *  eventVersion,
          *  pricedOrder.OrderVersion);*/
         return(false);
     }
 }
Ejemplo n.º 4
0
            public given_a_new_calculated_order()
            {
                this.sut.Handle(new OrderPlaced
                {
                    SourceId = orderId,
                    ReservationAutoExpiration = DateTime.UtcNow.AddMinutes(10),
                    Version = 2,
                });
                this.sut.Handle(new OrderTotalsCalculated
                {
                    SourceId = orderId,
                    Lines    = new[]
                    {
                        new SeatOrderLine
                        {
                            LineTotal = 50,
                            SeatType  = this.seatCreatedEvents[0].SourceId,
                            Quantity  = 10,
                            UnitPrice = 5
                        },
                        new SeatOrderLine
                        {
                            LineTotal = 10,
                            SeatType  = this.seatCreatedEvents[1].SourceId,
                            Quantity  = 1,
                            UnitPrice = 10
                        },
                    },
                    Total          = 60,
                    IsFreeOfCharge = true,
                    Version        = 9,
                });

                this.dto = this.dao.FindPricedOrder(orderId);
            }
        public void ThenTheRegistrantAssignsTheseSeats(Table table)
        {
            using (var orderController = RegistrationHelper.GetOrderController(conferenceInfo.Slug))
            {
                PricedOrder pricedOrder = null;
                var         timeout     = DateTime.Now.Add(Constants.UI.WaitTimeout);
                while ((pricedOrder == null || !pricedOrder.AssignmentsId.HasValue) && DateTime.Now < timeout)
                {
                    pricedOrder = RegistrationHelper.GetModel <PricedOrder>(orderController.Display(draftOrder.OrderId));
                }

                Assert.NotNull(pricedOrder);
                Assert.True(pricedOrder.AssignmentsId.HasValue);

                var orderSeats =
                    RegistrationHelper.GetModel <OrderSeats>(orderController.AssignSeats(pricedOrder.AssignmentsId.Value));

                foreach (var row in table.Rows)
                {
                    var seat = orderSeats.Seats.FirstOrDefault(s => s.SeatName == row["seat type"]);
                    Assert.NotNull(seat);
                    seat.Attendee.FirstName = row["first name"];
                    seat.Attendee.LastName  = row["last name"];
                    seat.Attendee.Email     = row["email address"];
                }

                orderController.AssignSeats(pricedOrder.AssignmentsId.Value, orderSeats.Seats.ToList());
            }
        }
Ejemplo n.º 6
0
        private bool WasNotAlreadyHandled(PricedOrder pricedOrder, int eventVersion)
        {
            if (eventVersion > pricedOrder.OrderVersion)
            {
                return(true);
            }
            else if (eventVersion == pricedOrder.OrderVersion)
            {
                Trace.TraceWarning(
                    "Ignoring duplicate priced order update message with version {1} for order id {0}",
                    pricedOrder.OrderId,
                    eventVersion);

                return(false);
            }
            else
            {
                Trace.TraceWarning(
                    @"Ignoring an older order update message was received with with version {1} for order id {0}, last known version {2}.
This read model generator has an expectation that the EventBus will deliver messages for the same source in order. Nevertheless, this warning can be expected in a migration scenario.",
                    pricedOrder.OrderId,
                    eventVersion,
                    pricedOrder.OrderVersion);
                return(false);
            }
        }
        public void Setup()
        {
            this._dbName = this.GetType().Name + "-" + Guid.NewGuid();
            using (var context = new ConferenceRegistrationDbContext(this._dbName)) {
                if (context.Database.Exists())
                {
                    context.Database.Delete();
                }

                context.Database.Create();
            }

            var blobStorage = new MemoryBlobStorage();

            this._sut = new PricedOrderViewModelGenerator(() => new ConferenceRegistrationDbContext(_dbName));
            this._dao = new OrderDao(() => new ConferenceRegistrationDbContext(_dbName), blobStorage,
                                     new JsonTextSerializer());

            this._seatCreatedEvents = new[]
            {
                new SeatCreated {
                    SourceId = Guid.NewGuid(), Name = "General"
                },
                new SeatCreated {
                    SourceId = Guid.NewGuid(), Name = "Precon"
                }
            };
            this._sut.Handle(this._seatCreatedEvents[0]);
            this._sut.Handle(this._seatCreatedEvents[1]);

            this._orderPlaced = new OrderPlaced {
                SourceId = _orderId,
                ReservationAutoExpiration = DateTime.UtcNow.AddMinutes(10),
                Version = 2,
            };

            this._sut.Handle(_orderPlaced);

            this._sut.Handle(new OrderTotalsCalculated {
                SourceId = _orderId,
                Lines    = new[]
                {
                    new SeatOrderLine
                    {
                        LineTotal = 50,
                        SeatType  = this._seatCreatedEvents[0].SourceId,
                        Quantity  = 10,
                        UnitPrice = 5
                    },
                },
                Total          = 50,
                IsFreeOfCharge = true,
                Version        = 4,
            });

            this._dto = this._dao.FindPricedOrder(_orderId);
        }
Ejemplo n.º 8
0
            public void then_order_placed_is_idempotent()
            {
                this.sut.Handle(orderPlaced);

                dto = this.dao.FindPricedOrder(orderId);

                Assert.NotNull(dto);
                Assert.InRange(dto.ReservationExpirationDate.Value, orderPlaced.ReservationAutoExpiration.AddSeconds(-1), orderPlaced.ReservationAutoExpiration.AddSeconds(1));
                Assert.Equal(orderPlaced.Version, dto.OrderVersion);
            }
Ejemplo n.º 9
0
            public void when_expired_then_deletes_priced_order()
            {
                this.sut.Handle(new OrderExpired {
                    SourceId = orderId
                });

                this.dto = this.dao.FindPricedOrder(orderId);

                Assert.Null(dto);
            }
        public void When_expired_Then_deletes_priced_order()
        {
            this._sut.Handle(new OrderExpired {
                SourceId = _orderId
            });

            this._dto = this._dao.FindPricedOrder(_orderId);

            Assert.IsNull(_dto);
        }
Ejemplo n.º 11
0
            public void when_confirmed_then_removes_expiration()
            {
                this.sut.Handle(new OrderConfirmed {
                    SourceId = orderId, Version = 15
                });

                this.dto = this.dao.FindPricedOrder(orderId);

                Assert.Null(dto.ReservationExpirationDate);
                Assert.Equal(15, dto.OrderVersion);
            }
        public void Handle(OrderPlaced @event)
        {
            var dto = new PricedOrder
            {
                OrderId = @event.SourceId,
                ReservationExpirationDate = @event.ReservationAutoExpiration,
                OrderVersion = @event.Version
            };

            pricedOrderRepository.Insert(dto);
        }
        public void then_order_placed_is_idempotent()
        {
            this._sut.Handle(_orderPlaced);

            _dto = this._dao.FindPricedOrder(_orderId);

            Assert.NotNull(_dto);
            Assert.IsTrue(_dto.ReservationExpirationDate.Value >= _orderPlaced.ReservationAutoExpiration.AddSeconds(-1) &&
                          _dto.ReservationExpirationDate.Value <= _orderPlaced.ReservationAutoExpiration.AddSeconds(1));
            Assert.AreEqual(_orderPlaced.Version, _dto.OrderVersion);
        }
        public void When_confirmed_Then_removes_expiration()
        {
            this._sut.Handle(new OrderConfirmed {
                SourceId = _orderId, Version = 15
            });

            this._dto = this._dao.FindPricedOrder(_orderId);

            Assert.IsNull(_dto.ReservationExpirationDate);
            Assert.AreEqual(15, _dto.OrderVersion);
        }
Ejemplo n.º 15
0
        private PaymentViewModel CompleteRegistrationWithThirdPartyProcessorPayment(PricedOrder order, int orderVersion)
        {
            var paymentCommand = CreatePaymentCommand(order);

            this._commandBus.Send(paymentCommand);

            return(new PaymentViewModel
            {
                ConferenceCode = this.ConferenceAlias.Code,
                PaymentId = paymentCommand.PaymentId
            });
        }
        public void Expiration_is_idempotent()
        {
            this._sut.Handle(new OrderExpired {
                SourceId = _orderId, Version = 15
            });
            this._sut.Handle(new OrderExpired {
                SourceId = _orderId, Version = 15
            });

            this._dto = this._dao.FindPricedOrder(_orderId);

            Assert.IsNull(_dto);
        }
Ejemplo n.º 17
0
            public void expiration_is_idempotent()
            {
                this.sut.Handle(new OrderExpired {
                    SourceId = orderId, Version = 15
                });
                this.sut.Handle(new OrderExpired {
                    SourceId = orderId, Version = 15
                });

                this.dto = this.dao.FindPricedOrder(orderId);

                Assert.Null(dto);
            }
        public void When_seat_assignments_created_Then_updates_order_with_assignments_id()
        {
            var assignmentsId = Guid.NewGuid();

            this._sut.Handle(new SeatAssignmentsCreated {
                SourceId = assignmentsId,
                OrderId  = _orderId,
            });

            this._dto = this._dao.FindPricedOrder(_orderId);

            Assert.AreEqual(assignmentsId, _dto.AssignmentsId);
            Assert.AreEqual(4, _dto.OrderVersion);
        }
Ejemplo n.º 19
0
            public void when_seat_assignments_created_then_updates_order_with_assignments_id()
            {
                var assignmentsId = Guid.NewGuid();

                sut.Handle(new SeatAssignmentsCreated {
                    SourceId = assignmentsId,
                    OrderId  = orderId
                });

                dto = dao.FindPricedOrder(orderId);

                Assert.Equal(assignmentsId, dto.AssignmentsId);
                Assert.Equal(4, dto.OrderVersion);
            }
        private InitiateThirdPartyProcessorPayment CreatePaymentCommand(PricedOrder order)
        {
            var description = "Registration for " + this.ConferenceAlias.Name;
            var totalAmount = order.Total;

            var paymentCommand = new InitiateThirdPartyProcessorPayment()
            {
                PaymentId       = GuidUtil.NewSequentialId(),
                ConferenceId    = this.ConferenceAlias.Id,
                PaymentSourceId = order.OrderId,
                Description     = description,
                TotalAmount     = totalAmount
            };

            return(paymentCommand);
        }
Ejemplo n.º 21
0
        public void when_display_valid_order_then_renders_view_with_priced_order()
        {
            // Arrange
            var orderId = Guid.NewGuid();
            var dto     = new PricedOrder {
                OrderId = orderId,
                Total   = 200
            };

            orderDao.Setup(r => r.FindPricedOrder(orderId)).Returns(dto);

            // Act
            var result = (ViewResult)sut.Display(orderId);

            // Assert
            Assert.NotNull(result);
            Assert.Equal(dto, result.Model);
        }
 public void Handle(OrderPlaced @event)
 {
     using (var context = contextFactory.Invoke()) {
         var dto = new PricedOrder {
             OrderId = @event.SourceId,
             ReservationExpirationDate = @event.ReservationAutoExpiration,
             OrderVersion = @event.Version
         };
         context.Set <PricedOrder>().Add(dto);
         try {
             context.SaveChanges();
         } catch (DbUpdateException) {
             Trace.TraceWarning(
                 "Ignoring OrderPlaced message with version {1} for order id {0}. This could be caused because the message was already handled and the PricedOrder entity was already created.",
                 dto.OrderId,
                 @event.Version);
         }
     }
 }
Ejemplo n.º 23
0
        private ActionResult CompleteRegistrationWithThirdPartyProcessorPayment(PricedOrder order, int orderVersion)
        {
            var paymentCommand = CreatePaymentCommand(order);

            commandBus.Send(paymentCommand);

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

            return(RedirectToAction(
                       "ThirdPartyProcessorPayment",
                       "Payment",
                       new {
                conferenceCode = ConferenceAlias.Code,
                paymentId = paymentCommand.PaymentId,
                paymentAcceptedUrl,
                paymentRejectedUrl
            }));
        }
Ejemplo n.º 24
0
            public given_a_calculated_order()
            {
                sut.Handle(new OrderTotalsCalculated {
                    SourceId = orderId,
                    Lines    = new[] {
                        new SeatOrderLine {
                            LineTotal = 50,
                            SeatType  = seatCreatedEvents[0].SourceId,
                            Quantity  = 10,
                            UnitPrice = 5
                        }
                    },
                    Total          = 50,
                    IsFreeOfCharge = true,
                    Version        = 4
                });

                dto = dao.FindPricedOrder(orderId);
            }
 public void Handle(OrderExpired @event)
 {
     // No need to keep this priced order alive if it is expired.
     using (var context = contextFactory.Invoke()) {
         var pricedOrder = new PricedOrder {
             OrderId = @event.SourceId
         };
         var set = context.Set <PricedOrder>();
         set.Attach(pricedOrder);
         set.Remove(pricedOrder);
         try {
             context.SaveChanges();
         } catch (DbUpdateConcurrencyException) {
             Trace.TraceWarning(
                 "Ignoring priced order expiration message with version {1} for order id {0}. This could be caused because the message was already handled and the entity was already deleted.",
                 pricedOrder.OrderId,
                 @event.Version);
         }
     }
 }
        public async Task Consume(ConsumeContext <OrderPlaced> consumeContext)
        {
            await using var repository = this.contextFactory.Invoke();
            var dto = new PricedOrder
            {
                OrderId = consumeContext.Message.SourceId,
                ReservationExpirationDate = consumeContext.Message.ReservationAutoExpiration,
                OrderVersion = consumeContext.Message.Version
            };

            repository.Set <PricedOrder>().Add(dto);
            try
            {
                await repository.SaveChangesAsync();
            }
            catch (DbUpdateException)
            {
                Trace.TraceWarning(
                    "Ignoring OrderPlaced message with version {1} for order id {0}. This could be caused because the message was already handled and the PricedOrder entity was already created.",
                    dto.OrderId,
                    consumeContext.Message.Version);
            }
        }
        public async Task Consume(ConsumeContext <OrderExpired> consumeContext)
        {
            // No need to keep this priced order alive if it is expired.
            await using var repository = this.contextFactory.Invoke();
            var pricedOrder = new PricedOrder {
                OrderId = consumeContext.Message.SourceId
            };
            var set = repository.Set <PricedOrder>();

            set.Attach(pricedOrder);
            set.Remove(pricedOrder);
            try
            {
                await repository.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                Trace.TraceWarning(
                    "Ignoring priced order expiration message with version {1} for order id {0}. This could be caused because the message was already handled and the entity was already deleted.",
                    pricedOrder.OrderId,
                    consumeContext.Message.Version);
            }
        }
Ejemplo n.º 28
0
 public when_reading_order()
 {
     this.dto = this.dao.FindPricedOrder(orderId);
 }
Ejemplo n.º 29
0
 public when_reading_order()
 {
     dto = dao.FindPricedOrder(orderId);
 }
        public void Handle(OrderTotalsCalculated @event)
        {
            var seatTypeIds = @event.Lines.OfType <SeatOrderLine>().Select(x => x.SeatType).Distinct().ToArray();

            using (var context = this.contextFactory.Invoke())
            {
                var dto = context.Query <PricedOrder>().Include(x => x.Lines).FirstOrDefault(x => x.OrderId == @event.SourceId);
                if (dto == null)
                {
                    dto = new PricedOrder {
                        OrderId = @event.SourceId
                    };
                    context.Set <PricedOrder>().Add(dto);
                }
                else if (WasNotAlreadyHandled(dto, @event.Version))
                {
                    var linesSet = context.Set <PricedOrderLine>();
                    foreach (var line in dto.Lines.ToList())
                    {
                        linesSet.Remove(line);
                    }
                }
                else
                {
                    // message already handled, skip.
                    return;
                }

                List <PricedOrderLineSeatTypeDescription> seatTypeDescriptions;
                if (seatTypeIds.Length != 0)
                {
                    seatTypeDescriptions = context.Query <PricedOrderLineSeatTypeDescription>()
                                           .Where(x => seatTypeIds.Contains(x.SeatTypeId))
                                           .ToList();
                }
                else
                {
                    seatTypeDescriptions = new List <PricedOrderLineSeatTypeDescription>();
                }

                foreach (var orderLine in @event.Lines)
                {
                    var line = new PricedOrderLine
                    {
                        LineTotal = orderLine.LineTotal
                    };

                    var seatOrderLine = orderLine as SeatOrderLine;
                    if (seatOrderLine != null)
                    {
                        // should we update the view model to avoid losing the SeatTypeId?
                        line.Description = seatTypeDescriptions.Where(x => x.SeatTypeId == seatOrderLine.SeatType).Select(x => x.Name).FirstOrDefault();
                        line.UnitPrice   = seatOrderLine.UnitPrice;
                        line.Quantity    = seatOrderLine.Quantity;
                    }

                    dto.Lines.Add(line);
                }

                dto.Total          = @event.Total;
                dto.IsFreeOfCharge = @event.IsFreeOfCharge;
                dto.OrderVersion   = @event.Version;

                context.SaveChanges();
            }
        }