From 520735ec3bb81fb9c86e96e5ec4bd1862724d1f0 Mon Sep 17 00:00:00 2001 From: Oskar Dudycz Date: Fri, 11 Mar 2022 14:09:45 +0100 Subject: [PATCH 1/3] Renamed Initialize Shopping Cart to Open Shopping Cart Added Cancel Shopping Cart operation Aligned Product Items implementation --- .../AddingProduct/AddProductTests.cs | 6 +- .../Canceling/CancelShoppingCartTests.cs | 78 +++++++++++++++++++ .../Confirming/ConfirmShoppingCartTests.cs | 6 +- .../OpenShoppingCartTests.cs} | 12 +-- .../RemovingProduct/RemoveProductTests.cs | 6 +- .../Controllers/ShoppingCartsController.cs | 21 ++++- .../Requests/Carts/ShoppingCartsRequests.cs | 2 +- .../Carts/Carts.Tests/Builders/CartBuilder.cs | 6 +- .../Carts/ConfirmingCart/ConfirmCartTests.cs | 2 +- .../InitializingCart/InitializeCartTests.cs | 6 +- ...=> OpenShoppingCardCommandHandlerTests.cs} | 12 +-- .../Extensions/Reservations/CartExtensions.cs | 11 ++- .../CancelingCart/CancelShoppingCart.cs | 49 ++++++++++++ .../CancelingCart/ShoppingCartCanceled.cs | 17 ++++ .../Carts/Carts/ShoppingCarts/Config.cs | 8 +- .../ConfirmingCart/ConfirmShoppingCart.cs | 4 +- .../GettingCartById/ShoppingCartDetails.cs | 18 ++++- .../GettingCartHistory/ShoppingCartHistory.cs | 14 +++- .../GettingCarts/ShoppingCartShortInfo.cs | 14 +++- .../ShoppingCartInitialized.cs | 20 ----- .../OpenShoppingCart.cs} | 18 ++--- .../OpeningCart/ShoppingCartOpened.cs | 17 ++++ .../Carts/Carts/ShoppingCarts/ShoppingCart.cs | 31 ++++++-- .../Carts/ShoppingCarts/ShoppingCartStatus.cs | 2 +- .../ECommerce/Orders/Orders/Orders/Order.cs | 4 +- .../Orders/Orders/Orders/OrderStatus.cs | 4 +- .../AddingProduct/AddProductTests.cs | 6 +- .../Canceling/CancelShoppingCartTests.cs | 74 ++++++++++++++++++ .../Confirming/ConfirmShoppingCartTests.cs | 6 +- .../OpenShoppingCartTests.cs} | 12 +-- .../RemovingProduct/RemoveProductTests.cs | 6 +- .../Controllers/ShoppingCartsController.cs | 29 +++++-- .../Requests/ShoppingCartsRequests.cs | 2 +- .../Carts/Carts.Tests/Builders/CartBuilder.cs | 6 +- .../Carts/ConfirmingCart/ConfirmCartTests.cs | 2 +- .../OpenCartCommandHandlerTests.cs} | 14 ++-- .../OpenCartTests.cs} | 12 +-- .../Extensions/Reservations/CartExtensions.cs | 10 +-- .../Products/FakeProductPriceCalculator.cs | 2 +- .../Pricing/RandomProductPriceCalculator.cs | 4 +- .../CancelingCart/CancelShoppingCart.cs | 50 ++++++++++++ .../CancelingCart/ShoppingCartCanceled.cs | 17 ++++ .../Carts/Carts/ShoppingCarts/Config.cs | 41 +++++----- .../GettingCartById/ShoppingCartDetails.cs | 31 +++++--- .../GettingCartHistory/CartHistory.cs | 39 ++++++---- .../GettingCarts/ShoppingCartShortInfo.cs | 29 ++++--- .../OpenShoppingCart.cs} | 18 ++--- .../ShoppingCartOpened.cs} | 8 +- .../Products/PricedProductItem.cs | 25 ++---- .../ShoppingCarts/Products/ProductItem.cs | 23 ++---- .../Carts/Carts/ShoppingCarts/ShoppingCart.cs | 46 ++++++++--- .../Carts/ShoppingCarts/ShoppingCartStatus.cs | 2 +- .../AddingProduct/AddProductTests.cs | 6 +- .../Canceling/CancelShoppingCartTests.cs | 74 ++++++++++++++++++ .../Confirming/ConfirmShoppingCartTests.cs | 6 +- .../OpenShoppingCartTests.cs} | 14 ++-- .../RemovingProduct/RemoveProductTests.cs | 6 +- .../Controllers/ShoppingCartsController.cs | 30 ++++--- .../Requests/ShoppingCartsRequests.cs | 2 +- .../Canceling/CancelShoppingCart.cs | 25 ++++++ .../ECommerce/ShoppingCarts/Configuration.cs | 23 ++++-- .../GettingCartById/ShoppingCartDetails.cs | 12 ++- .../GettingCarts/ShoppingCartShortInfo.cs | 30 ++++--- .../OpenShoppingCart.cs} | 14 ++-- .../ECommerce/ShoppingCarts/ShoppingCart.cs | 27 +++++-- .../EventsVersioning/ECommerce.V1/Events.cs | 2 +- .../Downcasters/ChangedStructure.cs | 16 ++-- .../SimpleMappings/NewNotRequiredProperty.cs | 10 +-- .../SimpleMappings/NewRequiredProperty.cs | 16 ++-- .../SimpleMappings/RenamedProperty.cs | 12 +-- ...eTransformationsWithDifferentEventTypes.cs | 20 ++--- .../Transformations/StreamTransformations.cs | 8 +- .../Upcasters/ChangedStructure.cs | 16 ++-- .../NewRequiredPropertyFromMetadata.cs | 16 ++-- Sample/EventsVersioning/README.md | 62 +++++++-------- 75 files changed, 946 insertions(+), 403 deletions(-) create mode 100644 Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Canceling/CancelShoppingCartTests.cs rename Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/{Initializing/InitializeShoppingCartTests.cs => Opening/OpenShoppingCartTests.cs} (79%) rename Sample/ECommerce/Carts/Carts.Tests/Carts/InitializingCart/{InitializeCardCommandHandlerTests.cs => OpenShoppingCardCommandHandlerTests.cs} (74%) create mode 100644 Sample/ECommerce/Carts/Carts/ShoppingCarts/CancelingCart/CancelShoppingCart.cs create mode 100644 Sample/ECommerce/Carts/Carts/ShoppingCarts/CancelingCart/ShoppingCartCanceled.cs delete mode 100644 Sample/ECommerce/Carts/Carts/ShoppingCarts/InitializingCart/ShoppingCartInitialized.cs rename Sample/ECommerce/Carts/Carts/ShoppingCarts/{InitializingCart/InitializeShoppingCart.cs => OpeningCart/OpenShoppingCart.cs} (65%) create mode 100644 Sample/ECommerce/Carts/Carts/ShoppingCarts/OpeningCart/ShoppingCartOpened.cs create mode 100644 Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Canceling/CancelShoppingCartTests.cs rename Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/{Initializing/InitializeShoppingCartTests.cs => Opening/OpenShoppingCartTests.cs} (79%) rename Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Carts/{InitializingCart/InitializeCartCommandHandlerTests.cs => OpeningCart/OpenCartCommandHandlerTests.cs} (70%) rename Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Carts/{InitializingCart/InitializeCartTests.cs => OpeningCart/OpenCartTests.cs} (71%) create mode 100644 Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/CancelingCart/CancelShoppingCart.cs create mode 100644 Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/CancelingCart/ShoppingCartCanceled.cs rename Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/{InitializingCart/InitializeShoppingCart.cs => OpeningCart/OpenShoppingCart.cs} (66%) rename Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/{InitializingCart/ShoppingCartInitialized.cs => OpeningCart/ShoppingCartOpened.cs} (59%) create mode 100644 Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/Canceling/CancelShoppingCartTests.cs rename Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/{Initializing/InitializeShoppingCartTests.cs => Opening/OpenShoppingCartTests.cs} (79%) create mode 100644 Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/Canceling/CancelShoppingCart.cs rename Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/{Initializing/InitializeShoppingCart.cs => Opening/OpenShoppingCart.cs} (54%) diff --git a/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/AddingProduct/AddProductTests.cs b/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/AddingProduct/AddProductTests.cs index cec6021d3..a22a34635 100644 --- a/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/AddingProduct/AddProductTests.cs +++ b/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/AddingProduct/AddProductTests.cs @@ -23,10 +23,10 @@ public class AddProductFixture: ApiWithEventsFixture public override async Task InitializeAsync() { - var initializeResponse = await Post(new InitializeShoppingCartRequest(ClientId)); - initializeResponse.EnsureSuccessStatusCode(); + var openResponse = await Post(new OpenShoppingCartRequest(ClientId)); + openResponse.EnsureSuccessStatusCode(); - ShoppingCartId = await initializeResponse.GetResultFromJson(); + ShoppingCartId = await openResponse.GetResultFromJson(); CommandResponse = await Post( $"{ShoppingCartId}/products", diff --git a/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Canceling/CancelShoppingCartTests.cs b/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Canceling/CancelShoppingCartTests.cs new file mode 100644 index 000000000..c295857bd --- /dev/null +++ b/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Canceling/CancelShoppingCartTests.cs @@ -0,0 +1,78 @@ +using System.Net; +using Carts.Api.Requests.Carts; +using Carts.ShoppingCarts; +using Carts.ShoppingCarts.FinalizingCart; +using Carts.ShoppingCarts.GettingCartById; +using Core.Api.Testing; +using Core.Testing; +using FluentAssertions; +using Xunit; + +namespace Carts.Api.Tests.ShoppingCarts.Canceling; + +public class ConfirmShoppingCartFixture: ApiWithEventsFixture +{ + protected override string ApiUrl => "/api/ShoppingCarts"; + + public Guid ShoppingCartId { get; private set; } + + public readonly Guid ClientId = Guid.NewGuid(); + + public HttpResponseMessage CommandResponse = default!; + + public override async Task InitializeAsync() + { + var openResponse = await Post(new OpenShoppingCartRequest(ClientId)); + openResponse.EnsureSuccessStatusCode(); + + ShoppingCartId = await openResponse.GetResultFromJson(); + + CommandResponse = await Delete( + $"{ShoppingCartId}", + new RequestOptions { IfMatch = 1.ToString() } + ); + } +} + +public class ConfirmShoppingCartTests: IClassFixture +{ + private readonly ConfirmShoppingCartFixture fixture; + + public ConfirmShoppingCartTests(ConfirmShoppingCartFixture fixture) + { + this.fixture = fixture; + } + + [Fact] + [Trait("Category", "Acceptance")] + public Task Put_Should_Return_OK() + { + var commandResponse = fixture.CommandResponse.EnsureSuccessStatusCode(); + commandResponse.StatusCode.Should().Be(HttpStatusCode.OK); + + return Task.CompletedTask; + } + + [Fact] + [Trait("Category", "Acceptance")] + public async Task Put_Should_Confirm_ShoppingCart() + { + // prepare query + var query = $"{fixture.ShoppingCartId}"; + + //send query + var queryResponse = await fixture.Get(query, 30, + check: async response => (await response.GetResultFromJson()).Version == 2); + + queryResponse.EnsureSuccessStatusCode(); + + var cartDetails = await queryResponse.GetResultFromJson(); + cartDetails.Should().NotBeNull(); + cartDetails.Id.Should().Be(fixture.ShoppingCartId); + cartDetails.Status.Should().Be(ShoppingCartStatus.Canceled); + cartDetails.ClientId.Should().Be(fixture.ClientId); + cartDetails.Version.Should().Be(2); + + fixture.PublishedExternalEventsOfType(); + } +} diff --git a/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Confirming/ConfirmShoppingCartTests.cs b/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Confirming/ConfirmShoppingCartTests.cs index fc32f8edf..6bbe73f46 100644 --- a/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Confirming/ConfirmShoppingCartTests.cs +++ b/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Confirming/ConfirmShoppingCartTests.cs @@ -22,10 +22,10 @@ public class ConfirmShoppingCartFixture: ApiWithEventsFixture public override async Task InitializeAsync() { - var initializeResponse = await Post(new InitializeShoppingCartRequest(ClientId)); - initializeResponse.EnsureSuccessStatusCode(); + var openResponse = await Post(new OpenShoppingCartRequest(ClientId)); + openResponse.EnsureSuccessStatusCode(); - ShoppingCartId = await initializeResponse.GetResultFromJson(); + ShoppingCartId = await openResponse.GetResultFromJson(); CommandResponse = await Put( $"{ShoppingCartId}/confirmation", diff --git a/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Initializing/InitializeShoppingCartTests.cs b/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Opening/OpenShoppingCartTests.cs similarity index 79% rename from Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Initializing/InitializeShoppingCartTests.cs rename to Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Opening/OpenShoppingCartTests.cs index 14351a07b..b695f7dd3 100644 --- a/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Initializing/InitializeShoppingCartTests.cs +++ b/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Opening/OpenShoppingCartTests.cs @@ -7,9 +7,9 @@ using FluentAssertions; using Xunit; -namespace Carts.Api.Tests.ShoppingCarts.Initializing; +namespace Carts.Api.Tests.ShoppingCarts.Opening; -public class InitializeShoppingCartFixture: ApiWithEventsFixture +public class OpenShoppingCartFixture: ApiWithEventsFixture { protected override string ApiUrl => "/api/ShoppingCarts"; @@ -19,15 +19,15 @@ public class InitializeShoppingCartFixture: ApiWithEventsFixture public override async Task InitializeAsync() { - CommandResponse = await Post(new InitializeShoppingCartRequest(ClientId)); + CommandResponse = await Post(new OpenShoppingCartRequest(ClientId)); } } -public class InitializeShoppingCartTests: IClassFixture +public class OpenShoppingCartTests: IClassFixture { - private readonly InitializeShoppingCartFixture fixture; + private readonly OpenShoppingCartFixture fixture; - public InitializeShoppingCartTests(InitializeShoppingCartFixture fixture) + public OpenShoppingCartTests(OpenShoppingCartFixture fixture) { this.fixture = fixture; } diff --git a/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/RemovingProduct/RemoveProductTests.cs b/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/RemovingProduct/RemoveProductTests.cs index 8eaf2d827..183a7dc6d 100644 --- a/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/RemovingProduct/RemoveProductTests.cs +++ b/Sample/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/RemovingProduct/RemoveProductTests.cs @@ -25,10 +25,10 @@ public class RemoveProductFixture: ApiWithEventsFixture public override async Task InitializeAsync() { - var initializeResponse = await Post(new InitializeShoppingCartRequest(ClientId)); - initializeResponse.EnsureSuccessStatusCode(); + var openResponse = await Post(new OpenShoppingCartRequest(ClientId)); + openResponse.EnsureSuccessStatusCode(); - ShoppingCartId = await initializeResponse.GetResultFromJson(); + ShoppingCartId = await openResponse.GetResultFromJson(); var addResponse = await Post( $"{ShoppingCartId}/products", diff --git a/Sample/ECommerce/Carts/Carts.Api/Controllers/ShoppingCartsController.cs b/Sample/ECommerce/Carts/Carts.Api/Controllers/ShoppingCartsController.cs index 1431e03dd..b7eb39711 100644 --- a/Sample/ECommerce/Carts/Carts.Api/Controllers/ShoppingCartsController.cs +++ b/Sample/ECommerce/Carts/Carts.Api/Controllers/ShoppingCartsController.cs @@ -1,10 +1,11 @@ using Carts.Api.Requests.Carts; +using Carts.ShoppingCarts.CancelingCart; using Carts.ShoppingCarts.ConfirmingCart; using Carts.ShoppingCarts.GettingCartAtVersion; using Carts.ShoppingCarts.GettingCartById; using Carts.ShoppingCarts.GettingCartHistory; using Carts.ShoppingCarts.GettingCarts; -using Carts.ShoppingCarts.InitializingCart; +using Carts.ShoppingCarts.OpeningCart; using Carts.ShoppingCarts.Products; using Microsoft.AspNetCore.Mvc; using Core.Commands; @@ -35,11 +36,11 @@ public ShoppingCartsController( } [HttpPost] - public async Task InitializeCart([FromBody] InitializeShoppingCartRequest? request) + public async Task OpenCart([FromBody] OpenShoppingCartRequest? request) { var cartId = idGenerator.New(); - var command = InitializeShoppingCart.Create( + var command = OpenShoppingCart.Create( cartId, request?.ClientId ); @@ -102,6 +103,20 @@ public async Task ConfirmCart(Guid id) return Ok(); } + + + [HttpDelete("{id}")] + public async Task CancelCart(Guid id) + { + var command = CancelShoppingCart.Create( + id + ); + + await commandBus.Send(command); + + return Ok(); + } + [HttpGet("{id}")] public async Task Get(Guid id) { diff --git a/Sample/ECommerce/Carts/Carts.Api/Requests/Carts/ShoppingCartsRequests.cs b/Sample/ECommerce/Carts/Carts.Api/Requests/Carts/ShoppingCartsRequests.cs index b7fdac561..6596578e3 100644 --- a/Sample/ECommerce/Carts/Carts.Api/Requests/Carts/ShoppingCartsRequests.cs +++ b/Sample/ECommerce/Carts/Carts.Api/Requests/Carts/ShoppingCartsRequests.cs @@ -1,6 +1,6 @@ namespace Carts.Api.Requests.Carts; -public record InitializeShoppingCartRequest( +public record OpenShoppingCartRequest( Guid? ClientId ); diff --git a/Sample/ECommerce/Carts/Carts.Tests/Builders/CartBuilder.cs b/Sample/ECommerce/Carts/Carts.Tests/Builders/CartBuilder.cs index 264793f8a..cfc741a30 100644 --- a/Sample/ECommerce/Carts/Carts.Tests/Builders/CartBuilder.cs +++ b/Sample/ECommerce/Carts/Carts.Tests/Builders/CartBuilder.cs @@ -7,13 +7,13 @@ internal class CartBuilder { private Func build = () => new ShoppingCart(); - public CartBuilder Initialized() + public CartBuilder Opened() { var cartId = Guid.NewGuid(); var clientId = Guid.NewGuid(); // When - var cart = ShoppingCart.Initialize( + var cart = ShoppingCart.Open( cartId, clientId ); @@ -31,4 +31,4 @@ public ShoppingCart Build() ((IAggregate)cart).DequeueUncommittedEvents(); return cart; } -} \ No newline at end of file +} diff --git a/Sample/ECommerce/Carts/Carts.Tests/Carts/ConfirmingCart/ConfirmCartTests.cs b/Sample/ECommerce/Carts/Carts.Tests/Carts/ConfirmingCart/ConfirmCartTests.cs index 71c09c998..70b314f05 100644 --- a/Sample/ECommerce/Carts/Carts.Tests/Carts/ConfirmingCart/ConfirmCartTests.cs +++ b/Sample/ECommerce/Carts/Carts.Tests/Carts/ConfirmingCart/ConfirmCartTests.cs @@ -15,7 +15,7 @@ public void ForTentativeCart_ShouldSucceed() // Given var cart = CartBuilder .Create() - .Initialized() + .Opened() .Build(); // When diff --git a/Sample/ECommerce/Carts/Carts.Tests/Carts/InitializingCart/InitializeCartTests.cs b/Sample/ECommerce/Carts/Carts.Tests/Carts/InitializingCart/InitializeCartTests.cs index 321a7b9fa..43118919f 100644 --- a/Sample/ECommerce/Carts/Carts.Tests/Carts/InitializingCart/InitializeCartTests.cs +++ b/Sample/ECommerce/Carts/Carts.Tests/Carts/InitializingCart/InitializeCartTests.cs @@ -14,7 +14,7 @@ public void ForValidParams_ShouldCreateCartWithPendingStatus() var clientId = Guid.NewGuid(); // When - var cart = ShoppingCart.Initialize( + var cart = ShoppingCart.Open( cartId, clientId ); @@ -22,11 +22,11 @@ public void ForValidParams_ShouldCreateCartWithPendingStatus() // Then cart - .IsInitializedCartWith( + .IsOpenedCartWith( cartId, clientId ) - .HasCartInitializedEventWith( + .HasCartOpenedEventWith( cartId, clientId ); diff --git a/Sample/ECommerce/Carts/Carts.Tests/Carts/InitializingCart/InitializeCardCommandHandlerTests.cs b/Sample/ECommerce/Carts/Carts.Tests/Carts/InitializingCart/OpenShoppingCardCommandHandlerTests.cs similarity index 74% rename from Sample/ECommerce/Carts/Carts.Tests/Carts/InitializingCart/InitializeCardCommandHandlerTests.cs rename to Sample/ECommerce/Carts/Carts.Tests/Carts/InitializingCart/OpenShoppingCardCommandHandlerTests.cs index abf417d92..d167fab4c 100644 --- a/Sample/ECommerce/Carts/Carts.Tests/Carts/InitializingCart/InitializeCardCommandHandlerTests.cs +++ b/Sample/ECommerce/Carts/Carts.Tests/Carts/InitializingCart/OpenShoppingCardCommandHandlerTests.cs @@ -1,5 +1,5 @@ using Carts.ShoppingCarts; -using Carts.ShoppingCarts.InitializingCart; +using Carts.ShoppingCarts.OpeningCart; using Carts.Tests.Extensions.Reservations; using Carts.Tests.Stubs.Events; using Carts.Tests.Stubs.Repositories; @@ -8,7 +8,7 @@ namespace Carts.Tests.Carts.InitializingCart; -public class InitializeCardCommandHandlerTests +public class OpenShoppingCardCommandHandlerTests { [Fact] public async Task ForInitCardCommand_ShouldAddNewCart() @@ -17,12 +17,12 @@ public async Task ForInitCardCommand_ShouldAddNewCart() var repository = new FakeRepository(); var scope = new DummyMartenAppendScope(); - var commandHandler = new HandleInitializeCart( + var commandHandler = new HandleOpenShoppingCart( repository, scope ); - var command = InitializeShoppingCart.Create(Guid.NewGuid(), Guid.NewGuid()); + var command = OpenShoppingCart.Create(Guid.NewGuid(), Guid.NewGuid()); // When await commandHandler.Handle(command, CancellationToken.None); @@ -33,11 +33,11 @@ public async Task ForInitCardCommand_ShouldAddNewCart() var cart = repository.Aggregates.Values.Single(); cart - .IsInitializedCartWith( + .IsOpenedCartWith( command.CartId, command.ClientId ) - .HasCartInitializedEventWith( + .HasCartOpenedEventWith( command.CartId, command.ClientId ); diff --git a/Sample/ECommerce/Carts/Carts.Tests/Extensions/Reservations/CartExtensions.cs b/Sample/ECommerce/Carts/Carts.Tests/Extensions/Reservations/CartExtensions.cs index f3a175923..d21ff6a21 100644 --- a/Sample/ECommerce/Carts/Carts.Tests/Extensions/Reservations/CartExtensions.cs +++ b/Sample/ECommerce/Carts/Carts.Tests/Extensions/Reservations/CartExtensions.cs @@ -1,5 +1,5 @@ using Carts.ShoppingCarts; -using Carts.ShoppingCarts.InitializingCart; +using Carts.ShoppingCarts.OpeningCart; using Core.Testing; using FluentAssertions; @@ -7,7 +7,7 @@ namespace Carts.Tests.Extensions.Reservations; internal static class CartExtensions { - public static ShoppingCart IsInitializedCartWith( + public static ShoppingCart IsOpenedCartWith( this ShoppingCart shoppingCart, Guid id, Guid clientId) @@ -23,18 +23,17 @@ public static ShoppingCart IsInitializedCartWith( return shoppingCart; } - public static ShoppingCart HasCartInitializedEventWith( + public static ShoppingCart HasCartOpenedEventWith( this ShoppingCart shoppingCart, Guid id, Guid clientId) { - var @event = shoppingCart.PublishedEvent(); + var @event = shoppingCart.PublishedEvent(); @event.Should().NotBeNull(); - @event.Should().BeOfType(); + @event.Should().BeOfType(); @event!.CartId.Should().Be(id); @event.ClientId.Should().Be(clientId); - @event.ShoppingCartStatus.Should().Be(ShoppingCartStatus.Pending); return shoppingCart; } diff --git a/Sample/ECommerce/Carts/Carts/ShoppingCarts/CancelingCart/CancelShoppingCart.cs b/Sample/ECommerce/Carts/Carts/ShoppingCarts/CancelingCart/CancelShoppingCart.cs new file mode 100644 index 000000000..17fcde6e8 --- /dev/null +++ b/Sample/ECommerce/Carts/Carts/ShoppingCarts/CancelingCart/CancelShoppingCart.cs @@ -0,0 +1,49 @@ +using Core.Commands; +using Core.Marten.Events; +using Core.Marten.Repository; +using MediatR; + +namespace Carts.ShoppingCarts.CancelingCart; + +public record CancelShoppingCart( + Guid CartId +): ICommand +{ + public static CancelShoppingCart Create(Guid cartId) + { + if (cartId == Guid.Empty) + throw new ArgumentOutOfRangeException(nameof(cartId)); + + return new CancelShoppingCart(cartId); + } +} + +internal class HandleCancelShoppingCart: + ICommandHandler +{ + private readonly IMartenRepository cartRepository; + private readonly IMartenAppendScope scope; + + public HandleCancelShoppingCart( + IMartenRepository cartRepository, + IMartenAppendScope scope + ) + { + this.cartRepository = cartRepository; + this.scope = scope; + } + + public async Task Handle(CancelShoppingCart command, CancellationToken cancellationToken) + { + await scope.Do((expectedVersion, traceMetadata) => + cartRepository.GetAndUpdate( + command.CartId, + cart => cart.Confirm(), + expectedVersion, + traceMetadata, + cancellationToken + ) + ); + return Unit.Value; + } +} diff --git a/Sample/ECommerce/Carts/Carts/ShoppingCarts/CancelingCart/ShoppingCartCanceled.cs b/Sample/ECommerce/Carts/Carts/ShoppingCarts/CancelingCart/ShoppingCartCanceled.cs new file mode 100644 index 000000000..b49106335 --- /dev/null +++ b/Sample/ECommerce/Carts/Carts/ShoppingCarts/CancelingCart/ShoppingCartCanceled.cs @@ -0,0 +1,17 @@ +namespace Carts.ShoppingCarts.CancelingCart; + +public record ShoppingCartCanceled( + Guid CartId, + DateTime CanceledAt +) +{ + public static ShoppingCartCanceled Create(Guid cartId, DateTime canceledAt) + { + if (cartId == Guid.Empty) + throw new ArgumentOutOfRangeException(nameof(cartId)); + if (canceledAt == default) + throw new ArgumentOutOfRangeException(nameof(canceledAt)); + + return new ShoppingCartCanceled(cartId, canceledAt); + } +} diff --git a/Sample/ECommerce/Carts/Carts/ShoppingCarts/Config.cs b/Sample/ECommerce/Carts/Carts/ShoppingCarts/Config.cs index 166ae28b9..4a3dc8b69 100644 --- a/Sample/ECommerce/Carts/Carts/ShoppingCarts/Config.cs +++ b/Sample/ECommerce/Carts/Carts/ShoppingCarts/Config.cs @@ -1,12 +1,13 @@ using Carts.Pricing; using Carts.ShoppingCarts.AddingProduct; +using Carts.ShoppingCarts.CancelingCart; using Carts.ShoppingCarts.ConfirmingCart; using Carts.ShoppingCarts.FinalizingCart; using Carts.ShoppingCarts.GettingCartAtVersion; using Carts.ShoppingCarts.GettingCartById; using Carts.ShoppingCarts.GettingCartHistory; using Carts.ShoppingCarts.GettingCarts; -using Carts.ShoppingCarts.InitializingCart; +using Carts.ShoppingCarts.OpeningCart; using Carts.ShoppingCarts.RemovingProduct; using Core.Commands; using Core.Events; @@ -28,10 +29,11 @@ internal static IServiceCollection AddCarts(this IServiceCollection services) => .AddEventHandlers(); private static IServiceCollection AddCommandHandlers(this IServiceCollection services) => - services.AddCommandHandler() + services.AddCommandHandler() .AddCommandHandler() .AddCommandHandler() - .AddCommandHandler(); + .AddCommandHandler() + .AddCommandHandler(); private static IServiceCollection AddQueryHandlers(this IServiceCollection services) => services.AddQueryHandler() diff --git a/Sample/ECommerce/Carts/Carts/ShoppingCarts/ConfirmingCart/ConfirmShoppingCart.cs b/Sample/ECommerce/Carts/Carts/ShoppingCarts/ConfirmingCart/ConfirmShoppingCart.cs index c48516ef0..2e47668ee 100644 --- a/Sample/ECommerce/Carts/Carts/ShoppingCarts/ConfirmingCart/ConfirmShoppingCart.cs +++ b/Sample/ECommerce/Carts/Carts/ShoppingCarts/ConfirmingCart/ConfirmShoppingCart.cs @@ -18,13 +18,13 @@ public static ConfirmShoppingCart Create(Guid cartId) } } -internal class HandleConfirmCart: +internal class HandleConfirmShoppingCart: ICommandHandler { private readonly IMartenRepository cartRepository; private readonly IMartenAppendScope scope; - public HandleConfirmCart( + public HandleConfirmShoppingCart( IMartenRepository cartRepository, IMartenAppendScope scope ) diff --git a/Sample/ECommerce/Carts/Carts/ShoppingCarts/GettingCartById/ShoppingCartDetails.cs b/Sample/ECommerce/Carts/Carts/ShoppingCarts/GettingCartById/ShoppingCartDetails.cs index f72e342d2..d94b0bb32 100644 --- a/Sample/ECommerce/Carts/Carts/ShoppingCarts/GettingCartById/ShoppingCartDetails.cs +++ b/Sample/ECommerce/Carts/Carts/ShoppingCarts/GettingCartById/ShoppingCartDetails.cs @@ -1,6 +1,7 @@ using Carts.ShoppingCarts.AddingProduct; +using Carts.ShoppingCarts.CancelingCart; using Carts.ShoppingCarts.ConfirmingCart; -using Carts.ShoppingCarts.InitializingCart; +using Carts.ShoppingCarts.OpeningCart; using Carts.ShoppingCarts.Products; using Carts.ShoppingCarts.RemovingProduct; using Core.Extensions; @@ -21,14 +22,14 @@ public class ShoppingCartDetails public int Version { get; set; } - public void Apply(ShoppingCartInitialized @event) + public void Apply(ShoppingCartOpened @event) { Version++; Id = @event.CartId; ClientId = @event.ClientId; ProductItems = new List(); - Status = @event.ShoppingCartStatus; + Status = ShoppingCartStatus.Pending; } public void Apply(ProductAdded @event) @@ -81,6 +82,13 @@ public void Apply(ShoppingCartConfirmed @event) Status = ShoppingCartStatus.Confirmed; } + public void Apply(ShoppingCartCanceled @event) + { + Version++; + + Status = ShoppingCartStatus.Canceled; + } + private PricedProductItem? FindProductItemMatchingWith(PricedProductItem productItem) { return ProductItems @@ -92,12 +100,14 @@ public class CartDetailsProjection : AggregateProjection { public CartDetailsProjection() { - ProjectEvent((item, @event) => item.Apply(@event)); + ProjectEvent((item, @event) => item.Apply(@event)); ProjectEvent((item, @event) => item.Apply(@event)); ProjectEvent((item, @event) => item.Apply(@event)); ProjectEvent((item, @event) => item.Apply(@event)); + + ProjectEvent((item, @event) => item.Apply(@event)); } } diff --git a/Sample/ECommerce/Carts/Carts/ShoppingCarts/GettingCartHistory/ShoppingCartHistory.cs b/Sample/ECommerce/Carts/Carts/ShoppingCarts/GettingCartHistory/ShoppingCartHistory.cs index 70eabddd1..af14e85ae 100644 --- a/Sample/ECommerce/Carts/Carts/ShoppingCarts/GettingCartHistory/ShoppingCartHistory.cs +++ b/Sample/ECommerce/Carts/Carts/ShoppingCarts/GettingCartHistory/ShoppingCartHistory.cs @@ -1,6 +1,7 @@ using Carts.ShoppingCarts.AddingProduct; +using Carts.ShoppingCarts.CancelingCart; using Carts.ShoppingCarts.ConfirmingCart; -using Carts.ShoppingCarts.InitializingCart; +using Carts.ShoppingCarts.OpeningCart; using Carts.ShoppingCarts.RemovingProduct; using Marten.Events; using Marten.Events.Projections; @@ -15,7 +16,7 @@ string Description public class CartHistoryTransformation : EventProjection { - public ShoppingCartHistory Transform(IEvent input) + public ShoppingCartHistory Transform(IEvent input) { return new ( Guid.NewGuid(), @@ -50,4 +51,13 @@ public ShoppingCartHistory Transform(IEvent input) $"Confirmed Cart with id `{input.Data.CartId}`" ); } + + public ShoppingCartHistory Transform(IEvent input) + { + return new ( + Guid.NewGuid(), + input.Data.CartId, + $"Canceled Cart with id `{input.Data.CartId}`" + ); + } } diff --git a/Sample/ECommerce/Carts/Carts/ShoppingCarts/GettingCarts/ShoppingCartShortInfo.cs b/Sample/ECommerce/Carts/Carts/ShoppingCarts/GettingCarts/ShoppingCartShortInfo.cs index 676326ac4..7c937d619 100644 --- a/Sample/ECommerce/Carts/Carts/ShoppingCarts/GettingCarts/ShoppingCartShortInfo.cs +++ b/Sample/ECommerce/Carts/Carts/ShoppingCarts/GettingCarts/ShoppingCartShortInfo.cs @@ -1,6 +1,7 @@ using Carts.ShoppingCarts.AddingProduct; +using Carts.ShoppingCarts.CancelingCart; using Carts.ShoppingCarts.ConfirmingCart; -using Carts.ShoppingCarts.InitializingCart; +using Carts.ShoppingCarts.OpeningCart; using Carts.ShoppingCarts.RemovingProduct; using Marten.Events.Aggregation; @@ -14,7 +15,7 @@ public class ShoppingCartShortInfo public ShoppingCartStatus Status { get; set; } - public void Apply(ShoppingCartInitialized @event) + public void Apply(ShoppingCartOpened @event) { Id = @event.CartId; TotalItemsCount = 0; @@ -35,18 +36,25 @@ public void Apply(ShoppingCartConfirmed @event) { Status = ShoppingCartStatus.Confirmed; } + + public void Apply(ShoppingCartCanceled @event) + { + Status = ShoppingCartStatus.Canceled; + } } public class CartShortInfoProjection : AggregateProjection { public CartShortInfoProjection() { - ProjectEvent((item, @event) => item.Apply(@event)); + ProjectEvent((item, @event) => item.Apply(@event)); ProjectEvent((item, @event) => item.Apply(@event)); ProjectEvent((item, @event) => item.Apply(@event)); ProjectEvent((item, @event) => item.Apply(@event)); + + ProjectEvent((item, @event) => item.Apply(@event)); } } diff --git a/Sample/ECommerce/Carts/Carts/ShoppingCarts/InitializingCart/ShoppingCartInitialized.cs b/Sample/ECommerce/Carts/Carts/ShoppingCarts/InitializingCart/ShoppingCartInitialized.cs deleted file mode 100644 index 7a889df06..000000000 --- a/Sample/ECommerce/Carts/Carts/ShoppingCarts/InitializingCart/ShoppingCartInitialized.cs +++ /dev/null @@ -1,20 +0,0 @@ -namespace Carts.ShoppingCarts.InitializingCart; - -public record ShoppingCartInitialized( - Guid CartId, - Guid ClientId, - ShoppingCartStatus ShoppingCartStatus -) -{ - public static ShoppingCartInitialized Create(Guid cartId, Guid clientId, ShoppingCartStatus shoppingCartStatus) - { - if (cartId == Guid.Empty) - throw new ArgumentOutOfRangeException(nameof(cartId)); - if (clientId == Guid.Empty) - throw new ArgumentOutOfRangeException(nameof(clientId)); - if (shoppingCartStatus == default) - throw new ArgumentOutOfRangeException(nameof(shoppingCartStatus)); - - return new ShoppingCartInitialized(cartId, clientId, shoppingCartStatus); - } -} diff --git a/Sample/ECommerce/Carts/Carts/ShoppingCarts/InitializingCart/InitializeShoppingCart.cs b/Sample/ECommerce/Carts/Carts/ShoppingCarts/OpeningCart/OpenShoppingCart.cs similarity index 65% rename from Sample/ECommerce/Carts/Carts/ShoppingCarts/InitializingCart/InitializeShoppingCart.cs rename to Sample/ECommerce/Carts/Carts/ShoppingCarts/OpeningCart/OpenShoppingCart.cs index aff105e72..ef4c9fc34 100644 --- a/Sample/ECommerce/Carts/Carts/ShoppingCarts/InitializingCart/InitializeShoppingCart.cs +++ b/Sample/ECommerce/Carts/Carts/ShoppingCarts/OpeningCart/OpenShoppingCart.cs @@ -3,31 +3,31 @@ using Core.Marten.Repository; using MediatR; -namespace Carts.ShoppingCarts.InitializingCart; +namespace Carts.ShoppingCarts.OpeningCart; -public record InitializeShoppingCart( +public record OpenShoppingCart( Guid CartId, Guid ClientId ): ICommand { - public static InitializeShoppingCart Create(Guid? cartId, Guid? clientId) + public static OpenShoppingCart Create(Guid? cartId, Guid? clientId) { if (cartId == null || cartId == Guid.Empty) throw new ArgumentOutOfRangeException(nameof(cartId)); if (clientId == null || clientId == Guid.Empty) throw new ArgumentOutOfRangeException(nameof(clientId)); - return new InitializeShoppingCart(cartId.Value, clientId.Value); + return new OpenShoppingCart(cartId.Value, clientId.Value); } } -internal class HandleInitializeCart: - ICommandHandler +internal class HandleOpenShoppingCart: + ICommandHandler { private readonly IMartenRepository cartRepository; private readonly IMartenAppendScope scope; - public HandleInitializeCart( + public HandleOpenShoppingCart( IMartenRepository cartRepository, IMartenAppendScope scope ) @@ -36,13 +36,13 @@ IMartenAppendScope scope this.scope = scope; } - public async Task Handle(InitializeShoppingCart command, CancellationToken cancellationToken) + public async Task Handle(OpenShoppingCart command, CancellationToken cancellationToken) { var (cartId, clientId) = command; await scope.Do((_, eventMetadata) => cartRepository.Add( - ShoppingCart.Initialize(cartId, clientId), + ShoppingCart.Open(cartId, clientId), eventMetadata, cancellationToken ) diff --git a/Sample/ECommerce/Carts/Carts/ShoppingCarts/OpeningCart/ShoppingCartOpened.cs b/Sample/ECommerce/Carts/Carts/ShoppingCarts/OpeningCart/ShoppingCartOpened.cs new file mode 100644 index 000000000..5dce90cab --- /dev/null +++ b/Sample/ECommerce/Carts/Carts/ShoppingCarts/OpeningCart/ShoppingCartOpened.cs @@ -0,0 +1,17 @@ +namespace Carts.ShoppingCarts.OpeningCart; + +public record ShoppingCartOpened( + Guid CartId, + Guid ClientId +) +{ + public static ShoppingCartOpened Create(Guid cartId, Guid clientId) + { + if (cartId == Guid.Empty) + throw new ArgumentOutOfRangeException(nameof(cartId)); + if (clientId == Guid.Empty) + throw new ArgumentOutOfRangeException(nameof(clientId)); + + return new ShoppingCartOpened(cartId, clientId); + } +} diff --git a/Sample/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCart.cs b/Sample/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCart.cs index 4d55846aa..c3209534d 100644 --- a/Sample/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCart.cs +++ b/Sample/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCart.cs @@ -1,7 +1,8 @@ using Carts.Pricing; using Carts.ShoppingCarts.AddingProduct; +using Carts.ShoppingCarts.CancelingCart; using Carts.ShoppingCarts.ConfirmingCart; -using Carts.ShoppingCarts.InitializingCart; +using Carts.ShoppingCarts.OpeningCart; using Carts.ShoppingCarts.Products; using Carts.ShoppingCarts.RemovingProduct; using Core.Aggregates; @@ -19,7 +20,7 @@ public class ShoppingCart: Aggregate public decimal TotalPrice => ProductItems.Sum(pi => pi.TotalPrice); - public static ShoppingCart Initialize( + public static ShoppingCart Open( Guid cartId, Guid clientId) { @@ -32,24 +33,22 @@ private ShoppingCart( Guid id, Guid clientId) { - var @event = ShoppingCartInitialized.Create( + var @event = ShoppingCartOpened.Create( id, - clientId, - ShoppingCartStatus.Pending + clientId ); Enqueue(@event); Apply(@event); } - public void Apply(ShoppingCartInitialized @event) + public void Apply(ShoppingCartOpened @event) { Version++; Id = @event.CartId; ClientId = @event.ClientId; ProductItems = new List(); - Status = @event.ShoppingCartStatus; } public void AddProduct( @@ -148,6 +147,24 @@ public void Apply(ShoppingCartConfirmed @event) Status = ShoppingCartStatus.Confirmed; } + public void Cancel() + { + if(Status != ShoppingCartStatus.Pending) + throw new InvalidOperationException($"Canceling cart in '{Status}' status is not allowed."); + + var @event = ShoppingCartCanceled.Create(Id, DateTime.UtcNow); + + Enqueue(@event); + Apply(@event); + } + + public void Apply(ShoppingCartCanceled @event) + { + Version++; + + Status = ShoppingCartStatus.Canceled; + } + private PricedProductItem? FindProductItemMatchingWith(PricedProductItem productItem) { return ProductItems diff --git a/Sample/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCartStatus.cs b/Sample/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCartStatus.cs index 092b1a3da..fe5f03cac 100644 --- a/Sample/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCartStatus.cs +++ b/Sample/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCartStatus.cs @@ -4,5 +4,5 @@ public enum ShoppingCartStatus { Pending = 1, Confirmed = 2, - Cancelled = 3 + Canceled = 3 } diff --git a/Sample/ECommerce/Orders/Orders/Orders/Order.cs b/Sample/ECommerce/Orders/Orders/Orders/Order.cs index 2778f74be..cef7e287f 100644 --- a/Sample/ECommerce/Orders/Orders/Orders/Order.cs +++ b/Sample/ECommerce/Orders/Orders/Orders/Order.cs @@ -56,7 +56,7 @@ public void Apply(OrderInitialized @event) Id = @event.OrderId; ClientId = @event.ClientId; ProductItems = @event.ProductItems; - Status = OrderStatus.Initialized; + Status = OrderStatus.Opened; } public void RecordPayment(Guid paymentId, DateTime recordedAt) @@ -116,4 +116,4 @@ public void Apply(OrderCancelled @event) Status = OrderStatus.Cancelled; } -} \ No newline at end of file +} diff --git a/Sample/ECommerce/Orders/Orders/Orders/OrderStatus.cs b/Sample/ECommerce/Orders/Orders/Orders/OrderStatus.cs index 9634fabeb..c6103209e 100644 --- a/Sample/ECommerce/Orders/Orders/Orders/OrderStatus.cs +++ b/Sample/ECommerce/Orders/Orders/Orders/OrderStatus.cs @@ -2,9 +2,9 @@ namespace Orders.Orders; public enum OrderStatus { - Initialized = 1, + Opened = 1, Paid = 2, Completed = 4, Cancelled = 8, Closed = Completed | Cancelled -} \ No newline at end of file +} diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/AddingProduct/AddProductTests.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/AddingProduct/AddProductTests.cs index 0a94fc21c..778f7ed09 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/AddingProduct/AddProductTests.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/AddingProduct/AddProductTests.cs @@ -22,10 +22,10 @@ public class AddProductFixture: ApiFixture public override async Task InitializeAsync() { - var initializeResponse = await Post(new InitializeShoppingCartRequest(ClientId)); - initializeResponse.EnsureSuccessStatusCode(); + var openResponse = await Post(new OpenShoppingCartRequest(ClientId)); + openResponse.EnsureSuccessStatusCode(); - ShoppingCartId = await initializeResponse.GetResultFromJson(); + ShoppingCartId = await openResponse.GetResultFromJson(); CommandResponse = await Post( $"{ShoppingCartId}/products", diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Canceling/CancelShoppingCartTests.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Canceling/CancelShoppingCartTests.cs new file mode 100644 index 000000000..1961d28a9 --- /dev/null +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Canceling/CancelShoppingCartTests.cs @@ -0,0 +1,74 @@ +using System.Net; +using Carts.Api.Requests; +using Carts.ShoppingCarts; +using Carts.ShoppingCarts.GettingCartById; +using Core.Api.Testing; +using FluentAssertions; +using Xunit; + +namespace Carts.Api.Tests.ShoppingCarts.Canceling; + +public class CancelShoppingCartFixture: ApiFixture +{ + protected override string ApiUrl => "/api/ShoppingCarts"; + + public Guid ShoppingCartId { get; private set; } + + public readonly Guid ClientId = Guid.NewGuid(); + + public HttpResponseMessage CommandResponse = default!; + + public override async Task InitializeAsync() + { + var openResponse = await Post(new OpenShoppingCartRequest(ClientId)); + openResponse.EnsureSuccessStatusCode(); + + ShoppingCartId = await openResponse.GetResultFromJson(); + + CommandResponse = await Delete( + $"{ShoppingCartId}", + new RequestOptions { IfMatch = 0.ToString() } + ); + } +} + +public class CancelShoppingCartTests: IClassFixture +{ + private readonly CancelShoppingCartFixture fixture; + + public CancelShoppingCartTests(CancelShoppingCartFixture fixture) + { + this.fixture = fixture; + } + + [Fact] + [Trait("Category", "Acceptance")] + public Task Put_Should_Return_OK() + { + var commandResponse = fixture.CommandResponse.EnsureSuccessStatusCode(); + commandResponse.StatusCode.Should().Be(HttpStatusCode.OK); + + return Task.CompletedTask; + } + + [Fact] + [Trait("Category", "Acceptance")] + public async Task Put_Should_Confirm_ShoppingCart() + { + // prepare query + var query = $"{fixture.ShoppingCartId}"; + + //send query + var queryResponse = await fixture.Get(query, 30, + check: async response => (await response.GetResultFromJson()).Version == 1); + + queryResponse.EnsureSuccessStatusCode(); + + var cartDetails = await queryResponse.GetResultFromJson(); + cartDetails.Should().NotBeNull(); + cartDetails.Id.Should().Be(fixture.ShoppingCartId); + cartDetails.Status.Should().Be(ShoppingCartStatus.Confirmed); + cartDetails.ClientId.Should().Be(fixture.ClientId); + cartDetails.Version.Should().Be(1); + } +} diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Confirming/ConfirmShoppingCartTests.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Confirming/ConfirmShoppingCartTests.cs index 7c75ef217..e34b0dd97 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Confirming/ConfirmShoppingCartTests.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Confirming/ConfirmShoppingCartTests.cs @@ -20,10 +20,10 @@ public class ConfirmShoppingCartFixture: ApiFixture public override async Task InitializeAsync() { - var initializeResponse = await Post(new InitializeShoppingCartRequest(ClientId)); - initializeResponse.EnsureSuccessStatusCode(); + var openResponse = await Post(new OpenShoppingCartRequest(ClientId)); + openResponse.EnsureSuccessStatusCode(); - ShoppingCartId = await initializeResponse.GetResultFromJson(); + ShoppingCartId = await openResponse.GetResultFromJson(); CommandResponse = await Put( $"{ShoppingCartId}/confirmation", diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Initializing/InitializeShoppingCartTests.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Opening/OpenShoppingCartTests.cs similarity index 79% rename from Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Initializing/InitializeShoppingCartTests.cs rename to Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Opening/OpenShoppingCartTests.cs index c2e438d55..c53e61bc0 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Initializing/InitializeShoppingCartTests.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Opening/OpenShoppingCartTests.cs @@ -6,9 +6,9 @@ using FluentAssertions; using Xunit; -namespace Carts.Api.Tests.ShoppingCarts.Initializing; +namespace Carts.Api.Tests.ShoppingCarts.Opening; -public class InitializeShoppingCartFixture: ApiFixture +public class OpenShoppingCartFixture: ApiFixture { protected override string ApiUrl => "/api/ShoppingCarts"; @@ -18,15 +18,15 @@ public class InitializeShoppingCartFixture: ApiFixture public override async Task InitializeAsync() { - CommandResponse = await Post(new InitializeShoppingCartRequest(ClientId)); + CommandResponse = await Post(new OpenShoppingCartRequest(ClientId)); } } -public class InitializeShoppingCartTests: IClassFixture +public class OpenShoppingCartTests: IClassFixture { - private readonly InitializeShoppingCartFixture fixture; + private readonly OpenShoppingCartFixture fixture; - public InitializeShoppingCartTests(InitializeShoppingCartFixture fixture) + public OpenShoppingCartTests(OpenShoppingCartFixture fixture) { this.fixture = fixture; } diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/RemovingProduct/RemoveProductTests.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/RemovingProduct/RemoveProductTests.cs index c57e7998f..126c31651 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/RemovingProduct/RemoveProductTests.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/RemovingProduct/RemoveProductTests.cs @@ -24,10 +24,10 @@ public class RemoveProductFixture: ApiFixture public override async Task InitializeAsync() { - var initializeResponse = await Post(new InitializeShoppingCartRequest(ClientId)); - initializeResponse.EnsureSuccessStatusCode(); + var openResponse = await Post(new OpenShoppingCartRequest(ClientId)); + openResponse.EnsureSuccessStatusCode(); - ShoppingCartId = await initializeResponse.GetResultFromJson(); + ShoppingCartId = await openResponse.GetResultFromJson(); var addResponse = await Post( $"{ShoppingCartId}/products", diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts.Api/Controllers/ShoppingCartsController.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts.Api/Controllers/ShoppingCartsController.cs index 94b1d3a7b..896893930 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts.Api/Controllers/ShoppingCartsController.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts.Api/Controllers/ShoppingCartsController.cs @@ -1,10 +1,11 @@ using Carts.Api.Requests; +using Carts.ShoppingCarts.CancelingCart; using Carts.ShoppingCarts.ConfirmingCart; using Carts.ShoppingCarts.GettingCartAtVersion; using Carts.ShoppingCarts.GettingCartById; using Carts.ShoppingCarts.GettingCartHistory; using Carts.ShoppingCarts.GettingCarts; -using Carts.ShoppingCarts.InitializingCart; +using Carts.ShoppingCarts.OpeningCart; using Carts.ShoppingCarts.Products; using Microsoft.AspNetCore.Mvc; using Core.Commands; @@ -35,11 +36,11 @@ public ShoppingCartsController( } [HttpPost] - public async Task InitializeCart([FromBody] InitializeShoppingCartRequest? request) + public async Task OpenCart([FromBody] OpenShoppingCartRequest? request) { var cartId = idGenerator.New(); - var command = InitializeShoppingCart.Create( + var command = OpenShoppingCart.Create( cartId, request?.ClientId ); @@ -57,7 +58,7 @@ [FromBody] AddProductRequest? request { var command = ShoppingCarts.AddingProduct.AddProduct.Create( id, - ProductItem.Create( + ProductItem.From( request?.ProductItem?.ProductId, request?.ProductItem?.Quantity ) @@ -78,9 +79,11 @@ public async Task RemoveProduct( { var command = ShoppingCarts.RemovingProduct.RemoveProduct.Create( id, - PricedProductItem.Create( - productId, - quantity, + PricedProductItem.From( + ProductItem.From( + productId, + quantity + ), unitPrice ) ); @@ -102,6 +105,18 @@ public async Task ConfirmCart(Guid id) return Ok(); } + [HttpDelete("{id}")] + public async Task CancelCart(Guid id) + { + var command = CancelShoppingCart.Create( + id + ); + + await commandBus.Send(command); + + return Ok(); + } + [HttpGet("{id}")] public async Task Get(Guid id) { diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts.Api/Requests/ShoppingCartsRequests.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts.Api/Requests/ShoppingCartsRequests.cs index 652037703..01b89fac0 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts.Api/Requests/ShoppingCartsRequests.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts.Api/Requests/ShoppingCartsRequests.cs @@ -1,6 +1,6 @@ namespace Carts.Api.Requests; -public record InitializeShoppingCartRequest( +public record OpenShoppingCartRequest( Guid? ClientId ); diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Builders/CartBuilder.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Builders/CartBuilder.cs index 7d44c4295..f3faea795 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Builders/CartBuilder.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Builders/CartBuilder.cs @@ -1,5 +1,5 @@ using Carts.ShoppingCarts; -using Carts.ShoppingCarts.InitializingCart; +using Carts.ShoppingCarts.OpeningCart; namespace Carts.Tests.Builders; @@ -7,12 +7,12 @@ internal class CartBuilder { private readonly Queue eventsToApply = new(); - public CartBuilder Initialized() + public CartBuilder Opened() { var cartId = Guid.NewGuid(); var clientId = Guid.NewGuid(); - eventsToApply.Enqueue(new ShoppingCartInitialized(cartId, clientId, ShoppingCartStatus.Pending)); + eventsToApply.Enqueue(new ShoppingCartOpened(cartId, clientId, ShoppingCartStatus.Pending)); return this; } diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Carts/ConfirmingCart/ConfirmCartTests.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Carts/ConfirmingCart/ConfirmCartTests.cs index f9feb50c2..6ea1462dd 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Carts/ConfirmingCart/ConfirmCartTests.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Carts/ConfirmingCart/ConfirmCartTests.cs @@ -15,7 +15,7 @@ public void ForTentativeCart_ShouldSucceed() // Given var cart = CartBuilder .Create() - .Initialized() + .Opened() .Build(); // When diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Carts/InitializingCart/InitializeCartCommandHandlerTests.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Carts/OpeningCart/OpenCartCommandHandlerTests.cs similarity index 70% rename from Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Carts/InitializingCart/InitializeCartCommandHandlerTests.cs rename to Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Carts/OpeningCart/OpenCartCommandHandlerTests.cs index f2be5d8bb..2a84f11d2 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Carts/InitializingCart/InitializeCartCommandHandlerTests.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Carts/OpeningCart/OpenCartCommandHandlerTests.cs @@ -1,14 +1,14 @@ using Carts.ShoppingCarts; -using Carts.ShoppingCarts.InitializingCart; +using Carts.ShoppingCarts.OpeningCart; using Carts.Tests.Extensions.Reservations; using Carts.Tests.Stubs.Events; using Carts.Tests.Stubs.Repositories; using FluentAssertions; using Xunit; -namespace Carts.Tests.Carts.InitializingCart; +namespace Carts.Tests.Carts.OpeningCart; -public class InitializeCartCommandHandlerTests +public class OpenCartCommandHandlerTests { [Fact] public async Task ForInitCardCommand_ShouldAddNewCart() @@ -17,12 +17,12 @@ public async Task ForInitCardCommand_ShouldAddNewCart() var repository = new FakeRepository(); var scope = new DummyEventStoreDBAppendScope(); - var commandHandler = new HandleInitializeCart( + var commandHandler = new HandleOpenCart( repository, scope ); - var command = InitializeShoppingCart.Create(Guid.NewGuid(), Guid.NewGuid()); + var command = OpenShoppingCart.Create(Guid.NewGuid(), Guid.NewGuid()); // When await commandHandler.Handle(command, CancellationToken.None); @@ -33,11 +33,11 @@ public async Task ForInitCardCommand_ShouldAddNewCart() var cart = repository.Aggregates.Values.Single(); cart - .IsInitializedCartWith( + .IsOpenedCartWith( command.CartId, command.ClientId ) - .HasCartInitializedEventWith( + .HasCartOpenedEventWith( command.CartId, command.ClientId ); diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Carts/InitializingCart/InitializeCartTests.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Carts/OpeningCart/OpenCartTests.cs similarity index 71% rename from Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Carts/InitializingCart/InitializeCartTests.cs rename to Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Carts/OpeningCart/OpenCartTests.cs index 321a7b9fa..25703b5ad 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Carts/InitializingCart/InitializeCartTests.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Carts/OpeningCart/OpenCartTests.cs @@ -2,9 +2,9 @@ using Carts.Tests.Extensions.Reservations; using Xunit; -namespace Carts.Tests.Carts.InitializingCart; +namespace Carts.Tests.Carts.OpeningCart; -public class InitializeCartTests +public class OpenCartTests { [Fact] public void ForValidParams_ShouldCreateCartWithPendingStatus() @@ -14,7 +14,7 @@ public void ForValidParams_ShouldCreateCartWithPendingStatus() var clientId = Guid.NewGuid(); // When - var cart = ShoppingCart.Initialize( + var cart = ShoppingCart.Open( cartId, clientId ); @@ -22,13 +22,13 @@ public void ForValidParams_ShouldCreateCartWithPendingStatus() // Then cart - .IsInitializedCartWith( + .IsOpenedCartWith( cartId, clientId ) - .HasCartInitializedEventWith( + .HasCartOpenedEventWith( cartId, clientId ); } -} \ No newline at end of file +} diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Extensions/Reservations/CartExtensions.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Extensions/Reservations/CartExtensions.cs index 9639c3d77..85111e800 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Extensions/Reservations/CartExtensions.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Extensions/Reservations/CartExtensions.cs @@ -1,5 +1,5 @@ using Carts.ShoppingCarts; -using Carts.ShoppingCarts.InitializingCart; +using Carts.ShoppingCarts.OpeningCart; using Core.Testing; using FluentAssertions; @@ -7,7 +7,7 @@ namespace Carts.Tests.Extensions.Reservations; internal static class CartExtensions { - public static ShoppingCart IsInitializedCartWith( + public static ShoppingCart IsOpenedCartWith( this ShoppingCart shoppingCart, Guid id, Guid clientId) @@ -23,15 +23,15 @@ public static ShoppingCart IsInitializedCartWith( return shoppingCart; } - public static ShoppingCart HasCartInitializedEventWith( + public static ShoppingCart HasCartOpenedEventWith( this ShoppingCart shoppingCart, Guid id, Guid clientId) { - var @event = shoppingCart.PublishedEvent(); + var @event = shoppingCart.PublishedEvent(); @event.Should().NotBeNull(); - @event.Should().BeOfType(); + @event.Should().BeOfType(); @event!.CartId.Should().Be(id); @event.ClientId.Should().Be(clientId); @event.ShoppingCartStatus.Should().Be(ShoppingCartStatus.Pending); diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Stubs/Products/FakeProductPriceCalculator.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Stubs/Products/FakeProductPriceCalculator.cs index e5591e6e2..0a5960f12 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Stubs/Products/FakeProductPriceCalculator.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts.Tests/Stubs/Products/FakeProductPriceCalculator.cs @@ -10,7 +10,7 @@ public IReadOnlyList Calculate(params ProductItem[] productIt { return productItems .Select(pi => - PricedProductItem.Create(pi, FakePrice)) + PricedProductItem.From(pi, FakePrice)) .ToList(); } } diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts/Pricing/RandomProductPriceCalculator.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts/Pricing/RandomProductPriceCalculator.cs index 693cbd33a..35b42dbc5 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts/Pricing/RandomProductPriceCalculator.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts/Pricing/RandomProductPriceCalculator.cs @@ -13,7 +13,7 @@ public IReadOnlyList Calculate(params ProductItem[] productIt return productItems .Select(pi => - PricedProductItem.Create(pi, (decimal)random.NextDouble() * 100)) + PricedProductItem.From(pi, (decimal)random.NextDouble() * 100)) .ToList(); } -} \ No newline at end of file +} diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/CancelingCart/CancelShoppingCart.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/CancelingCart/CancelShoppingCart.cs new file mode 100644 index 000000000..1125eb788 --- /dev/null +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/CancelingCart/CancelShoppingCart.cs @@ -0,0 +1,50 @@ +using Core.Commands; +using Core.EventStoreDB.OptimisticConcurrency; +using Core.EventStoreDB.Repository; +using MediatR; + +namespace Carts.ShoppingCarts.CancelingCart; + +public record CancelShoppingCart( + Guid CartId +): ICommand +{ + public static CancelShoppingCart Create(Guid? cartId) + { + if (cartId == null || cartId == Guid.Empty) + throw new ArgumentOutOfRangeException(nameof(cartId)); + + return new CancelShoppingCart(cartId.Value); + } +} + +internal class HandleCancelCart: + ICommandHandler +{ + private readonly IEventStoreDBRepository cartRepository; + private readonly IEventStoreDBAppendScope scope; + + public HandleCancelCart( + IEventStoreDBRepository cartRepository, + IEventStoreDBAppendScope scope + ) + { + this.cartRepository = cartRepository; + this.scope = scope; + } + + public async Task Handle(CancelShoppingCart command, CancellationToken cancellationToken) + { + await scope.Do((expectedRevision, eventMetadata) => + cartRepository.GetAndUpdate( + command.CartId, + cart => cart.Cancel(), + expectedRevision, + eventMetadata, + cancellationToken + ) + ); + + return Unit.Value; + } +} diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/CancelingCart/ShoppingCartCanceled.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/CancelingCart/ShoppingCartCanceled.cs new file mode 100644 index 000000000..55fcfedec --- /dev/null +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/CancelingCart/ShoppingCartCanceled.cs @@ -0,0 +1,17 @@ +namespace Carts.ShoppingCarts.CancelingCart; + +public record ShoppingCartCanceled( + Guid CartId, + DateTime CanceledAt +) +{ + public static ShoppingCartCanceled Create(Guid cartId, DateTime canceledAt) + { + if (cartId == Guid.Empty) + throw new ArgumentNullException(nameof(cartId)); + if (canceledAt == default) + throw new ArgumentNullException(nameof(canceledAt)); + + return new ShoppingCartCanceled(cartId, canceledAt); + } +} diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/Config.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/Config.cs index 34086d7e4..a439feccb 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/Config.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/Config.cs @@ -1,11 +1,12 @@ using Carts.Pricing; using Carts.ShoppingCarts.AddingProduct; +using Carts.ShoppingCarts.CancelingCart; using Carts.ShoppingCarts.ConfirmingCart; using Carts.ShoppingCarts.GettingCartAtVersion; using Carts.ShoppingCarts.GettingCartById; using Carts.ShoppingCarts.GettingCartHistory; using Carts.ShoppingCarts.GettingCarts; -using Carts.ShoppingCarts.InitializingCart; +using Carts.ShoppingCarts.OpeningCart; using Carts.ShoppingCarts.RemovingProduct; using Core.Commands; using Core.EventStoreDB.Repository; @@ -18,53 +19,51 @@ namespace Carts.ShoppingCarts; internal static class CartsConfig { - internal static IServiceCollection AddCarts(this IServiceCollection services) - { - return services.AddScoped() + internal static IServiceCollection AddCarts(this IServiceCollection services) => + services.AddScoped() .AddScoped, EventStoreDBRepository>() .AddCommandHandlers() .AddProjections() .AddQueryHandlers(); - } - private static IServiceCollection AddCommandHandlers(this IServiceCollection services) - { - return services - .AddCommandHandler() + private static IServiceCollection AddCommandHandlers(this IServiceCollection services) => + services + .AddCommandHandler() .AddCommandHandler() .AddCommandHandler() - .AddCommandHandler(); - } + .AddCommandHandler() + .AddCommandHandler(); private static IServiceCollection AddProjections(this IServiceCollection services) { services - .Project(@event => @event.CartId) + .Project(@event => @event.CartId) .Project(@event => @event.CartId) .Project(@event => @event.CartId) - .Project(@event => @event.CartId); + .Project(@event => @event.CartId) + .Project(@event => @event.CartId); services - .Project(@event => @event.CartId) + .Project(@event => @event.CartId) .Project(@event => @event.CartId) .Project(@event => @event.CartId) - .Project(@event => @event.CartId); + .Project(@event => @event.CartId) + .Project(@event => @event.CartId); services - .Project(@event => @event.CartId) + .Project(@event => @event.CartId) .Project(@event => @event.CartId) .Project(@event => @event.CartId) - .Project(@event => @event.CartId); + .Project(@event => @event.CartId) + .Project(@event => @event.CartId); return services; } - private static IServiceCollection AddQueryHandlers(this IServiceCollection services) - { - return services + private static IServiceCollection AddQueryHandlers(this IServiceCollection services) => + services .AddQueryHandler() .AddQueryHandler, HandleGetCarts>() .AddQueryHandler, HandleGetCartHistory>() .AddQueryHandler(); - } } diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/GettingCartById/ShoppingCartDetails.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/GettingCartById/ShoppingCartDetails.cs index 2d22ae3a8..1496e5d32 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/GettingCartById/ShoppingCartDetails.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/GettingCartById/ShoppingCartDetails.cs @@ -1,6 +1,7 @@ using Carts.ShoppingCarts.AddingProduct; +using Carts.ShoppingCarts.CancelingCart; using Carts.ShoppingCarts.ConfirmingCart; -using Carts.ShoppingCarts.InitializingCart; +using Carts.ShoppingCarts.OpeningCart; using Carts.ShoppingCarts.Products; using Carts.ShoppingCarts.RemovingProduct; using Core.Extensions; @@ -26,22 +27,25 @@ public void When(object @event) { switch (@event) { - case ShoppingCartInitialized cartInitialized: - Apply(cartInitialized); + case ShoppingCartOpened cartOpened: + Apply(cartOpened); return; - case ProductAdded cartInitialized: - Apply(cartInitialized); + case ProductAdded cartOpened: + Apply(cartOpened); return; - case ProductRemoved cartInitialized: - Apply(cartInitialized); + case ProductRemoved cartOpened: + Apply(cartOpened); return; - case ShoppingCartConfirmed cartInitialized: - Apply(cartInitialized); + case ShoppingCartConfirmed cartOpened: + Apply(cartOpened); + return; + case ShoppingCartCanceled cartCanceled: + Apply(cartCanceled); return; } } - public void Apply(ShoppingCartInitialized @event) + public void Apply(ShoppingCartOpened @event) { Id = @event.CartId; ClientId = @event.ClientId; @@ -100,6 +104,13 @@ public void Apply(ShoppingCartConfirmed @event) Status = ShoppingCartStatus.Confirmed; } + public void Apply(ShoppingCartCanceled @event) + { + Version++; + + Status = ShoppingCartStatus.Canceled; + } + private PricedProductItem? FindProductItemMatchingWith(PricedProductItem productItem) { return ProductItems diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/GettingCartHistory/CartHistory.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/GettingCartHistory/CartHistory.cs index 5f5a8aa5a..4de4cb7ff 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/GettingCartHistory/CartHistory.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/GettingCartHistory/CartHistory.cs @@ -1,6 +1,7 @@ using Carts.ShoppingCarts.AddingProduct; +using Carts.ShoppingCarts.CancelingCart; using Carts.ShoppingCarts.ConfirmingCart; -using Carts.ShoppingCarts.InitializingCart; +using Carts.ShoppingCarts.OpeningCart; using Carts.ShoppingCarts.RemovingProduct; using Core.Projections; @@ -17,46 +18,56 @@ public void When(object @event) { switch (@event) { - case ShoppingCartInitialized cartInitialized: - Apply(cartInitialized); + case ShoppingCartOpened cartOpened: + Apply(cartOpened); return; - case ProductAdded cartInitialized: - Apply(cartInitialized); + case ProductAdded cartOpened: + Apply(cartOpened); return; - case ProductRemoved cartInitialized: - Apply(cartInitialized); + case ProductRemoved cartOpened: + Apply(cartOpened); return; - case ShoppingCartConfirmed cartInitialized: - Apply(cartInitialized); + case ShoppingCartConfirmed cartOpened: + Apply(cartOpened); + return; + case ShoppingCartCanceled cartCanceled: + Apply(cartCanceled); return; } } - public void Apply(ShoppingCartInitialized @event) + public void Apply(ShoppingCartOpened @event) { Id = Guid.NewGuid(); CartId = @event.CartId; - Description = $"Created tentative Cart with id {@event.CartId}"; + Description = $"Opened Cart with id {@event.CartId}"; } public void Apply(ProductAdded @event) { Id = Guid.NewGuid(); CartId = @event.CartId; - Description = $"Created tentative Cart with id {@event.CartId}"; + Description = $"Added Product with id {@event.ProductItem.ProductId} to Cart with id {@event.CartId}"; } public void Apply(ProductRemoved @event) { Id = Guid.NewGuid(); CartId = @event.CartId; - Description = $"Created tentative Cart with id {@event.CartId}"; + Description = $"Removed Product with id {@event.ProductItem.ProductId} from Cart with id {@event.CartId}"; } public void Apply(ShoppingCartConfirmed @event) { Id = Guid.NewGuid(); CartId = @event.CartId; - Description = $"Created tentative Cart with id {@event.CartId}"; + Description = $"Confirmed Cart with id {@event.CartId}"; + } + + public void Apply(ShoppingCartCanceled @event) + { + Id = Guid.NewGuid(); + CartId = @event.CartId; + Description = $"Canceled Cart with id {@event.CartId}"; } } diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/GettingCarts/ShoppingCartShortInfo.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/GettingCarts/ShoppingCartShortInfo.cs index 144e03218..bc7fe42aa 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/GettingCarts/ShoppingCartShortInfo.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/GettingCarts/ShoppingCartShortInfo.cs @@ -1,6 +1,7 @@ using Carts.ShoppingCarts.AddingProduct; +using Carts.ShoppingCarts.CancelingCart; using Carts.ShoppingCarts.ConfirmingCart; -using Carts.ShoppingCarts.InitializingCart; +using Carts.ShoppingCarts.OpeningCart; using Carts.ShoppingCarts.RemovingProduct; using Core.Projections; @@ -20,22 +21,25 @@ public void When(object @event) { switch (@event) { - case ShoppingCartInitialized cartInitialized: - Apply(cartInitialized); + case ShoppingCartOpened cartOpened: + Apply(cartOpened); return; - case ProductAdded cartInitialized: - Apply(cartInitialized); + case ProductAdded cartOpened: + Apply(cartOpened); return; - case ProductRemoved cartInitialized: - Apply(cartInitialized); + case ProductRemoved cartOpened: + Apply(cartOpened); return; - case ShoppingCartConfirmed cartInitialized: - Apply(cartInitialized); + case ShoppingCartConfirmed cartOpened: + Apply(cartOpened); + return; + case ShoppingCartCanceled cartCanceled: + Apply(cartCanceled); return; } } - public void Apply(ShoppingCartInitialized @event) + public void Apply(ShoppingCartOpened @event) { Id = @event.CartId; TotalItemsCount = 0; @@ -56,4 +60,9 @@ public void Apply(ShoppingCartConfirmed @event) { Status = ShoppingCartStatus.Confirmed; } + + public void Apply(ShoppingCartCanceled @event) + { + Status = ShoppingCartStatus.Canceled; + } } diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/InitializingCart/InitializeShoppingCart.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/OpeningCart/OpenShoppingCart.cs similarity index 66% rename from Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/InitializingCart/InitializeShoppingCart.cs rename to Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/OpeningCart/OpenShoppingCart.cs index c9c2f909c..e9f0f8163 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/InitializingCart/InitializeShoppingCart.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/OpeningCart/OpenShoppingCart.cs @@ -3,31 +3,31 @@ using Core.EventStoreDB.Repository; using MediatR; -namespace Carts.ShoppingCarts.InitializingCart; +namespace Carts.ShoppingCarts.OpeningCart; -public record InitializeShoppingCart( +public record OpenShoppingCart( Guid CartId, Guid ClientId ): ICommand { - public static InitializeShoppingCart Create(Guid? cartId, Guid? clientId) + public static OpenShoppingCart Create(Guid? cartId, Guid? clientId) { if (cartId == null || cartId == Guid.Empty) throw new ArgumentOutOfRangeException(nameof(cartId)); if (clientId == null || clientId == Guid.Empty) throw new ArgumentOutOfRangeException(nameof(clientId)); - return new InitializeShoppingCart(cartId.Value, clientId.Value); + return new OpenShoppingCart(cartId.Value, clientId.Value); } } -internal class HandleInitializeCart: - ICommandHandler +internal class HandleOpenCart: + ICommandHandler { private readonly IEventStoreDBRepository cartRepository; private readonly IEventStoreDBAppendScope scope; - public HandleInitializeCart( + public HandleOpenCart( IEventStoreDBRepository cartRepository, IEventStoreDBAppendScope scope ) @@ -36,13 +36,13 @@ IEventStoreDBAppendScope scope this.scope = scope; } - public async Task Handle(InitializeShoppingCart command, CancellationToken cancellationToken) + public async Task Handle(OpenShoppingCart command, CancellationToken cancellationToken) { var (cartId, clientId) = command; await scope.Do((_, eventMetadata) => cartRepository.Add( - ShoppingCart.Initialize(cartId, clientId), + ShoppingCart.Open(cartId, clientId), eventMetadata, cancellationToken ) diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/InitializingCart/ShoppingCartInitialized.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/OpeningCart/ShoppingCartOpened.cs similarity index 59% rename from Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/InitializingCart/ShoppingCartInitialized.cs rename to Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/OpeningCart/ShoppingCartOpened.cs index 7a889df06..fd66aeace 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/InitializingCart/ShoppingCartInitialized.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/OpeningCart/ShoppingCartOpened.cs @@ -1,12 +1,12 @@ -namespace Carts.ShoppingCarts.InitializingCart; +namespace Carts.ShoppingCarts.OpeningCart; -public record ShoppingCartInitialized( +public record ShoppingCartOpened( Guid CartId, Guid ClientId, ShoppingCartStatus ShoppingCartStatus ) { - public static ShoppingCartInitialized Create(Guid cartId, Guid clientId, ShoppingCartStatus shoppingCartStatus) + public static ShoppingCartOpened Create(Guid cartId, Guid clientId, ShoppingCartStatus shoppingCartStatus) { if (cartId == Guid.Empty) throw new ArgumentOutOfRangeException(nameof(cartId)); @@ -15,6 +15,6 @@ public static ShoppingCartInitialized Create(Guid cartId, Guid clientId, Shoppin if (shoppingCartStatus == default) throw new ArgumentOutOfRangeException(nameof(shoppingCartStatus)); - return new ShoppingCartInitialized(cartId, clientId, shoppingCartStatus); + return new ShoppingCartOpened(cartId, clientId, shoppingCartStatus); } } diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/Products/PricedProductItem.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/Products/PricedProductItem.cs index 250964906..70ea9ccf0 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/Products/PricedProductItem.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/Products/PricedProductItem.cs @@ -1,31 +1,16 @@ namespace Carts.ShoppingCarts.Products; -public class PricedProductItem +public record PricedProductItem( + ProductItem ProductItem, + decimal UnitPrice +) { public Guid ProductId => ProductItem.ProductId; - public int Quantity => ProductItem.Quantity; - public decimal UnitPrice { get; } - public decimal TotalPrice => Quantity * UnitPrice; - public ProductItem ProductItem { get; } - - private PricedProductItem(ProductItem productItem, decimal unitPrice) - { - ProductItem = productItem; - UnitPrice = unitPrice; - } - - public static PricedProductItem Create(Guid? productId, int? quantity, decimal? unitPrice) - { - return Create( - ProductItem.Create(productId, quantity), - unitPrice - ); - } - public static PricedProductItem Create(ProductItem productItem, decimal? unitPrice) + public static PricedProductItem From(ProductItem productItem, decimal? unitPrice) { return unitPrice switch { diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/Products/ProductItem.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/Products/ProductItem.cs index 76e0b3fe1..c3455fd5a 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/Products/ProductItem.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/Products/ProductItem.cs @@ -1,18 +1,11 @@ namespace Carts.ShoppingCarts.Products; -public class ProductItem +public record ProductItem( + Guid ProductId, + int Quantity +) { - public Guid ProductId { get; } - - public int Quantity { get; } - - private ProductItem(Guid productId, int quantity) - { - ProductId = productId; - Quantity = quantity; - } - - public static ProductItem Create(Guid? productId, int? quantity) + public static ProductItem From(Guid? productId, int? quantity) { if (!productId.HasValue) throw new ArgumentNullException(nameof(productId)); @@ -30,7 +23,7 @@ public ProductItem MergeWith(ProductItem productItem) if (!MatchesProduct(productItem)) throw new ArgumentException("Product does not match."); - return Create(ProductId, Quantity + productItem.Quantity); + return From(ProductId, Quantity + productItem.Quantity); } public ProductItem Substract(ProductItem productItem) @@ -38,7 +31,7 @@ public ProductItem Substract(ProductItem productItem) if (!MatchesProduct(productItem)) throw new ArgumentException("Product does not match."); - return Create(ProductId, Quantity - productItem.Quantity); + return From(ProductId, Quantity - productItem.Quantity); } public bool MatchesProduct(ProductItem productItem) @@ -55,4 +48,4 @@ public bool HasTheSameQuantity(ProductItem productItem) { return Quantity == productItem.Quantity; } -} \ No newline at end of file +} diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCart.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCart.cs index bf7aa3bde..65fd7ca4e 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCart.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCart.cs @@ -1,7 +1,8 @@ using Carts.Pricing; using Carts.ShoppingCarts.AddingProduct; +using Carts.ShoppingCarts.CancelingCart; using Carts.ShoppingCarts.ConfirmingCart; -using Carts.ShoppingCarts.InitializingCart; +using Carts.ShoppingCarts.OpeningCart; using Carts.ShoppingCarts.Products; using Carts.ShoppingCarts.RemovingProduct; using Core.Aggregates; @@ -19,7 +20,7 @@ public class ShoppingCart: Aggregate public decimal TotalPrice => ProductItems.Sum(pi => pi.TotalPrice); - public static ShoppingCart Initialize( + public static ShoppingCart Open( Guid cartId, Guid clientId) { @@ -32,17 +33,20 @@ public override void When(object @event) { switch (@event) { - case ShoppingCartInitialized cartInitialized: - Apply(cartInitialized); + case ShoppingCartOpened cartOpened: + Apply(cartOpened); return; - case ProductAdded cartInitialized: - Apply(cartInitialized); + case ProductAdded cartOpened: + Apply(cartOpened); return; - case ProductRemoved cartInitialized: - Apply(cartInitialized); + case ProductRemoved cartOpened: + Apply(cartOpened); return; - case ShoppingCartConfirmed cartInitialized: - Apply(cartInitialized); + case ShoppingCartConfirmed cartOpened: + Apply(cartOpened); + return; + case ShoppingCartCanceled cartCanceled: + Apply(cartCanceled); return; } } @@ -51,7 +55,7 @@ private ShoppingCart( Guid id, Guid clientId) { - var @event = ShoppingCartInitialized.Create( + var @event = ShoppingCartOpened.Create( id, clientId, ShoppingCartStatus.Pending @@ -61,7 +65,7 @@ private ShoppingCart( Apply(@event); } - private void Apply(ShoppingCartInitialized @event) + private void Apply(ShoppingCartOpened @event) { Version = 0; @@ -167,6 +171,24 @@ private void Apply(ShoppingCartConfirmed @event) Status = ShoppingCartStatus.Confirmed; } + public void Cancel() + { + if(Status != ShoppingCartStatus.Pending) + throw new InvalidOperationException($"Confirming cart in '{Status}' status is not allowed."); + + var @event = ShoppingCartCanceled.Create(Id, DateTime.UtcNow); + + Enqueue(@event); + Apply(@event); + } + + private void Apply(ShoppingCartCanceled @event) + { + Version++; + + Status = ShoppingCartStatus.Canceled; + } + private PricedProductItem? FindProductItemMatchingWith(PricedProductItem productItem) { return ProductItems diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCartStatus.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCartStatus.cs index 092b1a3da..fe5f03cac 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCartStatus.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCartStatus.cs @@ -4,5 +4,5 @@ public enum ShoppingCartStatus { Pending = 1, Confirmed = 2, - Cancelled = 3 + Canceled = 3 } diff --git a/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/AddingProduct/AddProductTests.cs b/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/AddingProduct/AddProductTests.cs index 45771b914..7e2713003 100644 --- a/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/AddingProduct/AddProductTests.cs +++ b/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/AddingProduct/AddProductTests.cs @@ -22,10 +22,10 @@ public class AddProductFixture: ApiFixture public override async Task InitializeAsync() { - var initializeResponse = await Post(new InitializeShoppingCartRequest(ClientId)); - initializeResponse.EnsureSuccessStatusCode(); + var openResponse = await Post(new OpenShoppingCartRequest(ClientId)); + openResponse.EnsureSuccessStatusCode(); - ShoppingCartId = await initializeResponse.GetResultFromJson(); + ShoppingCartId = await openResponse.GetResultFromJson(); CommandResponse = await Post( $"{ShoppingCartId}/products", diff --git a/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/Canceling/CancelShoppingCartTests.cs b/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/Canceling/CancelShoppingCartTests.cs new file mode 100644 index 000000000..658ce77b7 --- /dev/null +++ b/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/Canceling/CancelShoppingCartTests.cs @@ -0,0 +1,74 @@ +using System.Net; +using Core.Api.Testing; +using ECommerce.Api.Requests; +using ECommerce.ShoppingCarts; +using ECommerce.ShoppingCarts.GettingCartById; +using FluentAssertions; +using Xunit; + +namespace ECommerce.Api.Tests.ShoppingCarts.Canceling; + +public class CancelShoppingCartFixture: ApiFixture +{ + protected override string ApiUrl => "/api/ShoppingCarts"; + + public Guid ShoppingCartId { get; private set; } + + public readonly Guid ClientId = Guid.NewGuid(); + + public HttpResponseMessage CommandResponse = default!; + + public override async Task InitializeAsync() + { + var openResponse = await Post(new OpenShoppingCartRequest(ClientId)); + openResponse.EnsureSuccessStatusCode(); + + ShoppingCartId = await openResponse.GetResultFromJson(); + + CommandResponse = await Delete( + $"{ShoppingCartId}", + new RequestOptions { IfMatch = 0.ToString() } + ); + } +} + +public class CancelShoppingCartTests: IClassFixture +{ + private readonly CancelShoppingCartFixture fixture; + + public CancelShoppingCartTests(CancelShoppingCartFixture fixture) + { + this.fixture = fixture; + } + + [Fact] + [Trait("Category", "Acceptance")] + public Task Put_Should_Return_OK() + { + var commandResponse = fixture.CommandResponse.EnsureSuccessStatusCode(); + commandResponse.StatusCode.Should().Be(HttpStatusCode.OK); + + return Task.CompletedTask; + } + + [Fact] + [Trait("Category", "Acceptance")] + public async Task Put_Should_Confirm_ShoppingCart() + { + // prepare query + var query = $"{fixture.ShoppingCartId}"; + + //send query + var queryResponse = await fixture.Get(query, 30, + check: async response => (await response.GetResultFromJson()).Version == 1); + + queryResponse.EnsureSuccessStatusCode(); + + var cartDetails = await queryResponse.GetResultFromJson(); + cartDetails.Should().NotBeNull(); + cartDetails.Id.Should().Be(fixture.ShoppingCartId); + cartDetails.Status.Should().Be(ShoppingCartStatus.Confirmed); + cartDetails.ClientId.Should().Be(fixture.ClientId); + cartDetails.Version.Should().Be(1); + } +} diff --git a/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/Confirming/ConfirmShoppingCartTests.cs b/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/Confirming/ConfirmShoppingCartTests.cs index c902039c4..4d81de1aa 100644 --- a/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/Confirming/ConfirmShoppingCartTests.cs +++ b/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/Confirming/ConfirmShoppingCartTests.cs @@ -20,10 +20,10 @@ public class ConfirmShoppingCartFixture: ApiFixture public override async Task InitializeAsync() { - var initializeResponse = await Post(new InitializeShoppingCartRequest(ClientId)); - initializeResponse.EnsureSuccessStatusCode(); + var openResponse = await Post(new OpenShoppingCartRequest(ClientId)); + openResponse.EnsureSuccessStatusCode(); - ShoppingCartId = await initializeResponse.GetResultFromJson(); + ShoppingCartId = await openResponse.GetResultFromJson(); CommandResponse = await Put( $"{ShoppingCartId}/confirmation", diff --git a/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/Initializing/InitializeShoppingCartTests.cs b/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/Opening/OpenShoppingCartTests.cs similarity index 79% rename from Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/Initializing/InitializeShoppingCartTests.cs rename to Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/Opening/OpenShoppingCartTests.cs index d7bc81f78..3db5fb93b 100644 --- a/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/Initializing/InitializeShoppingCartTests.cs +++ b/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/Opening/OpenShoppingCartTests.cs @@ -6,9 +6,9 @@ using FluentAssertions; using Xunit; -namespace ECommerce.Api.Tests.ShoppingCarts.Initializing; +namespace ECommerce.Api.Tests.ShoppingCarts.Opening; -public class InitializeShoppingCartFixture: ApiFixture +public class OpenShoppingCartFixture: ApiFixture { protected override string ApiUrl => "/api/ShoppingCarts"; @@ -18,15 +18,15 @@ public class InitializeShoppingCartFixture: ApiFixture public override async Task InitializeAsync() { - CommandResponse = await Post(new InitializeShoppingCartRequest(ClientId)); + CommandResponse = await Post(new OpenShoppingCartRequest(ClientId)); } } -public class InitializeShoppingCartTests: IClassFixture +public class OpenShoppingCartTests: IClassFixture { - private readonly InitializeShoppingCartFixture fixture; + private readonly OpenShoppingCartFixture fixture; - public InitializeShoppingCartTests(InitializeShoppingCartFixture fixture) + public OpenShoppingCartTests(OpenShoppingCartFixture fixture) { this.fixture = fixture; } @@ -64,4 +64,4 @@ public async Task Post_Should_Create_ShoppingCart() cartDetails.ClientId.Should().Be(fixture.ClientId); cartDetails.Version.Should().Be(0); } -} \ No newline at end of file +} diff --git a/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/RemovingProduct/RemoveProductTests.cs b/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/RemovingProduct/RemoveProductTests.cs index 293d76265..23131e807 100644 --- a/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/RemovingProduct/RemoveProductTests.cs +++ b/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/RemovingProduct/RemoveProductTests.cs @@ -24,10 +24,10 @@ public class RemoveProductFixture: ApiFixture public override async Task InitializeAsync() { - var initializeResponse = await Post(new InitializeShoppingCartRequest(ClientId)); - initializeResponse.EnsureSuccessStatusCode(); + var openResponse = await Post(new OpenShoppingCartRequest(ClientId)); + openResponse.EnsureSuccessStatusCode(); - ShoppingCartId = await initializeResponse.GetResultFromJson(); + ShoppingCartId = await openResponse.GetResultFromJson(); var addResponse = await Post( $"{ShoppingCartId}/products", diff --git a/Sample/EventStoreDB/Simple/ECommerce.Api/Controllers/ShoppingCartsController.cs b/Sample/EventStoreDB/Simple/ECommerce.Api/Controllers/ShoppingCartsController.cs index 991e28287..87fdd2d12 100644 --- a/Sample/EventStoreDB/Simple/ECommerce.Api/Controllers/ShoppingCartsController.cs +++ b/Sample/EventStoreDB/Simple/ECommerce.Api/Controllers/ShoppingCartsController.cs @@ -2,10 +2,11 @@ using Microsoft.AspNetCore.Mvc; using ECommerce.Api.Requests; using ECommerce.ShoppingCarts.AddingProductItem; +using ECommerce.ShoppingCarts.Canceling; using ECommerce.ShoppingCarts.Confirming; using ECommerce.ShoppingCarts.GettingCartById; using ECommerce.ShoppingCarts.GettingCarts; -using ECommerce.ShoppingCarts.Initializing; +using ECommerce.ShoppingCarts.Opening; using ECommerce.ShoppingCarts.ProductItems; using ECommerce.ShoppingCarts.RemovingProductItem; @@ -15,10 +16,10 @@ namespace ECommerce.Api.Controllers; public class ShoppingCartsController: Controller { [HttpPost] - public async Task InitializeCart( + public async Task OpenCart( [FromServices] Func generateId, - [FromServices] Func handle, - [FromBody] InitializeShoppingCartRequest? request, + [FromServices] Func handle, + [FromBody] OpenShoppingCartRequest? request, CancellationToken ct ) { @@ -27,7 +28,7 @@ CancellationToken ct var cartId = generateId(); - var command = InitializeShoppingCart.From( + var command = OpenShoppingCart.From( cartId, request.ClientId ); @@ -91,15 +92,24 @@ CancellationToken ct public async Task ConfirmCart( [FromServices] Func handle, Guid id, - [FromBody] ConfirmShoppingCartRequest request, CancellationToken ct ) { - if (request == null) - throw new ArgumentNullException(nameof(request)); + var command = ConfirmShoppingCart.From(id); + + await handle(command, ct); - var command = - ConfirmShoppingCart.From(id); + return Ok(); + } + + [HttpDelete("{id}")] + public async Task CancelCart( + [FromServices] Func handle, + Guid id, + CancellationToken ct + ) + { + var command = CancelShoppingCart.From(id); await handle(command, ct); diff --git a/Sample/EventStoreDB/Simple/ECommerce.Api/Requests/ShoppingCartsRequests.cs b/Sample/EventStoreDB/Simple/ECommerce.Api/Requests/ShoppingCartsRequests.cs index aafe77457..de8679fc8 100644 --- a/Sample/EventStoreDB/Simple/ECommerce.Api/Requests/ShoppingCartsRequests.cs +++ b/Sample/EventStoreDB/Simple/ECommerce.Api/Requests/ShoppingCartsRequests.cs @@ -1,6 +1,6 @@ namespace ECommerce.Api.Requests; -public record InitializeShoppingCartRequest( +public record OpenShoppingCartRequest( Guid? ClientId ); diff --git a/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/Canceling/CancelShoppingCart.cs b/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/Canceling/CancelShoppingCart.cs new file mode 100644 index 000000000..911f91766 --- /dev/null +++ b/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/Canceling/CancelShoppingCart.cs @@ -0,0 +1,25 @@ +namespace ECommerce.ShoppingCarts.Canceling; + +public record CancelShoppingCart( + Guid ShoppingCartId +) +{ + public static CancelShoppingCart From(Guid? cartId) + { + if (cartId == null || cartId == Guid.Empty) + throw new ArgumentOutOfRangeException(nameof(cartId)); + + return new CancelShoppingCart(cartId.Value); + } + + public static ShoppingCartCanceled Handle(CancelShoppingCart command, ShoppingCart shoppingCart) + { + if(shoppingCart.IsClosed) + throw new InvalidOperationException($"Confirming cart in '{shoppingCart.Status}' status is not allowed."); + + return new ShoppingCartCanceled( + shoppingCart.Id, + DateTime.UtcNow + ); + } +} diff --git a/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/Configuration.cs b/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/Configuration.cs index cd3d9acce..bbe0daa23 100644 --- a/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/Configuration.cs +++ b/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/Configuration.cs @@ -2,10 +2,11 @@ using ECommerce.Core.Projections; using ECommerce.Pricing.ProductPricing; using ECommerce.ShoppingCarts.AddingProductItem; +using ECommerce.ShoppingCarts.Canceling; using ECommerce.ShoppingCarts.Confirming; using ECommerce.ShoppingCarts.GettingCartById; using ECommerce.ShoppingCarts.GettingCarts; -using ECommerce.ShoppingCarts.Initializing; +using ECommerce.ShoppingCarts.Opening; using ECommerce.ShoppingCarts.RemovingProductItem; using ECommerce.Storage; using Microsoft.EntityFrameworkCore; @@ -21,8 +22,8 @@ public static IServiceCollection AddShoppingCartsModule(this IServiceCollection ShoppingCart.Default, ShoppingCart.When, builder => builder - .AddOn( - InitializeShoppingCart.Handle, + .AddOn( + OpenShoppingCart.Handle, command => ShoppingCart.MapToStreamId(command.ShoppingCartId) ) .UpdateOn( @@ -43,10 +44,14 @@ public static IServiceCollection AddShoppingCartsModule(this IServiceCollection ConfirmShoppingCart.Handle, command => ShoppingCart.MapToStreamId(command.ShoppingCartId) ) + .UpdateOn( + CancelShoppingCart.Handle, + command => ShoppingCart.MapToStreamId(command.ShoppingCartId) + ) ) .For( builder => builder - .AddOn(ShoppingCartDetailsProjection.Handle) + .AddOn(ShoppingCartDetailsProjection.Handle) .UpdateOn( e => e.ShoppingCartId, ShoppingCartDetailsProjection.Handle, @@ -61,11 +66,15 @@ public static IServiceCollection AddShoppingCartsModule(this IServiceCollection e => e.ShoppingCartId, ShoppingCartDetailsProjection.Handle ) + .UpdateOn( + e => e.ShoppingCartId, + ShoppingCartDetailsProjection.Handle + ) .QueryWith(GetCartById.Handle) ) .For( builder => builder - .AddOn(ShoppingCartShortInfoProjection.Handle) + .AddOn(ShoppingCartShortInfoProjection.Handle) .UpdateOn( e => e.ShoppingCartId, ShoppingCartShortInfoProjection.Handle @@ -78,6 +87,10 @@ public static IServiceCollection AddShoppingCartsModule(this IServiceCollection e => e.ShoppingCartId, ShoppingCartShortInfoProjection.Handle ) + .UpdateOn( + e => e.ShoppingCartId, + ShoppingCartShortInfoProjection.Handle + ) .QueryWith(GetCarts.Handle) ); diff --git a/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/GettingCartById/ShoppingCartDetails.cs b/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/GettingCartById/ShoppingCartDetails.cs index c8a381f79..f3268b0b7 100644 --- a/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/GettingCartById/ShoppingCartDetails.cs +++ b/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/GettingCartById/ShoppingCartDetails.cs @@ -21,7 +21,7 @@ public class ShoppingCartDetailsProductItem public static class ShoppingCartDetailsProjection { - public static ShoppingCartDetails Handle(EventEnvelope eventEnvelope) + public static ShoppingCartDetails Handle(EventEnvelope eventEnvelope) { var (shoppingCartId, clientId) = eventEnvelope.Data; @@ -45,6 +45,16 @@ public static void Handle(EventEnvelope eventEnvelope, Sh view.LastProcessedPosition = eventEnvelope.Metadata.LogPosition; } + public static void Handle(EventEnvelope eventEnvelope, ShoppingCartDetails view) + { + if (view.LastProcessedPosition >= eventEnvelope.Metadata.LogPosition) + return; + + view.Status = ShoppingCartStatus.Canceled; + view.Version++; + view.LastProcessedPosition = eventEnvelope.Metadata.LogPosition; + } + public static void Handle(EventEnvelope eventEnvelope, ShoppingCartDetails view) { if (view.LastProcessedPosition >= eventEnvelope.Metadata.LogPosition) diff --git a/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/GettingCarts/ShoppingCartShortInfo.cs b/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/GettingCarts/ShoppingCartShortInfo.cs index 4710e9f14..c888907a7 100644 --- a/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/GettingCarts/ShoppingCartShortInfo.cs +++ b/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/GettingCarts/ShoppingCartShortInfo.cs @@ -16,7 +16,7 @@ public record ShoppingCartShortInfo public class ShoppingCartShortInfoProjection { - public static ShoppingCartShortInfo Handle(EventEnvelope eventEnvelope) + public static ShoppingCartShortInfo Handle(EventEnvelope eventEnvelope) { var (shoppingCartId, clientId) = eventEnvelope.Data; @@ -31,38 +31,48 @@ public static ShoppingCartShortInfo Handle(EventEnvelope eventEnvelope, ShoppingCartShortInfo view) + public static void Handle(EventEnvelope eventEnvelope, ShoppingCartShortInfo view) { if (view.LastProcessedPosition >= eventEnvelope.Metadata.LogPosition) return; - view.Status = ShoppingCartStatus.Confirmed; + var productItem = eventEnvelope.Data.ProductItem; + + view.TotalItemsCount += productItem.Quantity; + view.TotalPrice += productItem.TotalPrice; view.Version++; view.LastProcessedPosition = eventEnvelope.Metadata.LogPosition; } - public static void Handle(EventEnvelope eventEnvelope, ShoppingCartShortInfo view) + public static void Handle(EventEnvelope eventEnvelope, ShoppingCartShortInfo view) { if (view.LastProcessedPosition >= eventEnvelope.Metadata.LogPosition) return; var productItem = eventEnvelope.Data.ProductItem; - view.TotalItemsCount += productItem.Quantity; - view.TotalPrice += productItem.TotalPrice; + view.TotalItemsCount -= productItem.Quantity; + view.TotalPrice -= productItem.TotalPrice; view.Version++; view.LastProcessedPosition = eventEnvelope.Metadata.LogPosition; } - public static void Handle(EventEnvelope eventEnvelope, ShoppingCartShortInfo view) + public static void Handle(EventEnvelope eventEnvelope, ShoppingCartShortInfo view) { if (view.LastProcessedPosition >= eventEnvelope.Metadata.LogPosition) return; - var productItem = eventEnvelope.Data.ProductItem; + view.Status = ShoppingCartStatus.Confirmed; + view.Version++; + view.LastProcessedPosition = eventEnvelope.Metadata.LogPosition; + } - view.TotalItemsCount -= productItem.Quantity; - view.TotalPrice -= productItem.TotalPrice; + public static void Handle(EventEnvelope eventEnvelope, ShoppingCartShortInfo view) + { + if (view.LastProcessedPosition >= eventEnvelope.Metadata.LogPosition) + return; + + view.Status = ShoppingCartStatus.Canceled; view.Version++; view.LastProcessedPosition = eventEnvelope.Metadata.LogPosition; } diff --git a/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/Initializing/InitializeShoppingCart.cs b/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/Opening/OpenShoppingCart.cs similarity index 54% rename from Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/Initializing/InitializeShoppingCart.cs rename to Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/Opening/OpenShoppingCart.cs index 96edf3c08..ed4e8a085 100644 --- a/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/Initializing/InitializeShoppingCart.cs +++ b/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/Opening/OpenShoppingCart.cs @@ -1,27 +1,27 @@ -namespace ECommerce.ShoppingCarts.Initializing; +namespace ECommerce.ShoppingCarts.Opening; -public record InitializeShoppingCart( +public record OpenShoppingCart( Guid ShoppingCartId, Guid ClientId ) { - public static InitializeShoppingCart From(Guid? cartId, Guid? clientId) + public static OpenShoppingCart From(Guid? cartId, Guid? clientId) { if (cartId == null || cartId == Guid.Empty) throw new ArgumentOutOfRangeException(nameof(cartId)); if (clientId == null || clientId == Guid.Empty) throw new ArgumentOutOfRangeException(nameof(clientId)); - return new InitializeShoppingCart(cartId.Value, clientId.Value); + return new OpenShoppingCart(cartId.Value, clientId.Value); } - public static ShoppingCartInitialized Handle(InitializeShoppingCart command) + public static ShoppingCartOpened Handle(OpenShoppingCart command) { var (shoppingCartId, clientId) = command; - return new ShoppingCartInitialized( + return new ShoppingCartOpened( shoppingCartId, clientId ); } -} \ No newline at end of file +} diff --git a/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/ShoppingCart.cs b/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/ShoppingCart.cs index 174857294..d9679980e 100644 --- a/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/ShoppingCart.cs +++ b/Sample/EventStoreDB/Simple/ECommerce/ShoppingCarts/ShoppingCart.cs @@ -2,7 +2,7 @@ namespace ECommerce.ShoppingCarts; -public record ShoppingCartInitialized( +public record ShoppingCartOpened( Guid ShoppingCartId, Guid ClientId ); @@ -22,13 +22,18 @@ public record ShoppingCartConfirmed( DateTime ConfirmedAt ); +public record ShoppingCartCanceled( + Guid ShoppingCartId, + DateTime CanceledAt +); + public enum ShoppingCartStatus { Pending = 1, Confirmed = 2, - Cancelled = 4, + Canceled = 4, - Closed = Confirmed | Cancelled + Closed = Confirmed | Canceled } public record ShoppingCart( @@ -36,7 +41,8 @@ public record ShoppingCart( Guid ClientId, ShoppingCartStatus Status, ProductItemsList ProductItems, - DateTime? ConfirmedAt = null + DateTime? ConfirmedAt = null, + DateTime? CanceledAt = null ) { public bool IsClosed { get; } = Status.HasFlag(ShoppingCartStatus.Closed); @@ -45,7 +51,7 @@ public static ShoppingCart When(ShoppingCart entity, object @event) { return @event switch { - ShoppingCartInitialized (var cartId, var clientId) => + ShoppingCartOpened (var cartId, var clientId) => entity with { Id = cartId, @@ -72,13 +78,20 @@ entity with Status = ShoppingCartStatus.Confirmed, ConfirmedAt = confirmedAt }, + + ShoppingCartCanceled (_, var canceledAt) => + entity with + { + Status = ShoppingCartStatus.Canceled, + CanceledAt = canceledAt + }, _ => entity }; } public static ShoppingCart Default() => - new (default, default, default, ProductItemsList.Empty(), default); + new (default, default, default, ProductItemsList.Empty(), default, default); public static string MapToStreamId(Guid shoppingCartId) => $"ShoppingCart-{shoppingCartId}"; -} \ No newline at end of file +} diff --git a/Sample/EventsVersioning/ECommerce.V1/Events.cs b/Sample/EventsVersioning/ECommerce.V1/Events.cs index 6bad062fe..bdf458c83 100644 --- a/Sample/EventsVersioning/ECommerce.V1/Events.cs +++ b/Sample/EventsVersioning/ECommerce.V1/Events.cs @@ -10,7 +10,7 @@ public record PricedProductItem( decimal UnitPrice ); -public record ShoppingCartInitialized( +public record ShoppingCartOpened( Guid ShoppingCartId, Guid ClientId ); diff --git a/Sample/EventsVersioning/EventsVersioning.Tests/Downcasters/ChangedStructure.cs b/Sample/EventsVersioning/EventsVersioning.Tests/Downcasters/ChangedStructure.cs index 37381b2f6..5c27820eb 100644 --- a/Sample/EventsVersioning/EventsVersioning.Tests/Downcasters/ChangedStructure.cs +++ b/Sample/EventsVersioning/EventsVersioning.Tests/Downcasters/ChangedStructure.cs @@ -12,28 +12,28 @@ public record Client( string Name = "Unknown" ); - public record ShoppingCartInitialized( + public record ShoppingCartOpened( Guid ShoppingCartId, Client Client ); -public static V1.ShoppingCartInitialized Downcast( - ShoppingCartInitialized newEvent +public static V1.ShoppingCartOpened Downcast( + ShoppingCartOpened newEvent ) { - return new V1.ShoppingCartInitialized( + return new V1.ShoppingCartOpened( newEvent.ShoppingCartId, newEvent.Client.Id ); } -public static V1.ShoppingCartInitialized Downcast( +public static V1.ShoppingCartOpened Downcast( string newEventJson ) { var newEvent = JsonDocument.Parse(newEventJson).RootElement; - return new V1.ShoppingCartInitialized( + return new V1.ShoppingCartOpened( newEvent.GetProperty("ShoppingCartId").GetGuid(), newEvent.GetProperty("Client").GetProperty("Id").GetGuid() ); @@ -43,7 +43,7 @@ string newEventJson public void UpcastObjects_Should_BeForwardCompatible() { // Given - var newEvent = new ShoppingCartInitialized( + var newEvent = new ShoppingCartOpened( Guid.NewGuid(), new Client( Guid.NewGuid(), "Oskar the Grouch") ); @@ -60,7 +60,7 @@ public void UpcastObjects_Should_BeForwardCompatible() public void UpcastJson_Should_BeForwardCompatible() { // Given - var newEvent = new ShoppingCartInitialized( + var newEvent = new ShoppingCartOpened( Guid.NewGuid(), new Client( Guid.NewGuid(), "Oskar the Grouch") ); diff --git a/Sample/EventsVersioning/EventsVersioning.Tests/SimpleMappings/NewNotRequiredProperty.cs b/Sample/EventsVersioning/EventsVersioning.Tests/SimpleMappings/NewNotRequiredProperty.cs index 9850f643b..44130e6da 100644 --- a/Sample/EventsVersioning/EventsVersioning.Tests/SimpleMappings/NewNotRequiredProperty.cs +++ b/Sample/EventsVersioning/EventsVersioning.Tests/SimpleMappings/NewNotRequiredProperty.cs @@ -7,7 +7,7 @@ namespace EventsVersioning.Tests.SimpleMappings; public class NewNotRequiredProperty { - public record ShoppingCartInitialized( + public record ShoppingCartOpened( Guid ShoppingCartId, Guid ClientId, // Adding new not required property as nullable @@ -18,11 +18,11 @@ public record ShoppingCartInitialized( public void Should_BeForwardCompatible() { // Given - var oldEvent = new V1.ShoppingCartInitialized(Guid.NewGuid(), Guid.NewGuid()); + var oldEvent = new V1.ShoppingCartOpened(Guid.NewGuid(), Guid.NewGuid()); var json = JsonSerializer.Serialize(oldEvent); // When - var @event = JsonSerializer.Deserialize(json); + var @event = JsonSerializer.Deserialize(json); @event.Should().NotBeNull(); @event!.ShoppingCartId.Should().Be(oldEvent.ShoppingCartId); @@ -34,11 +34,11 @@ public void Should_BeForwardCompatible() public void Should_BeBackwardCompatible() { // Given - var @event = new ShoppingCartInitialized(Guid.NewGuid(), Guid.NewGuid(), DateTime.UtcNow); + var @event = new ShoppingCartOpened(Guid.NewGuid(), Guid.NewGuid(), DateTime.UtcNow); var json = JsonSerializer.Serialize(@event); // When - var oldEvent = JsonSerializer.Deserialize(json); + var oldEvent = JsonSerializer.Deserialize(json); oldEvent.Should().NotBeNull(); oldEvent!.ShoppingCartId.Should().Be(@event.ShoppingCartId); diff --git a/Sample/EventsVersioning/EventsVersioning.Tests/SimpleMappings/NewRequiredProperty.cs b/Sample/EventsVersioning/EventsVersioning.Tests/SimpleMappings/NewRequiredProperty.cs index e10310ed6..46f2be5f7 100644 --- a/Sample/EventsVersioning/EventsVersioning.Tests/SimpleMappings/NewRequiredProperty.cs +++ b/Sample/EventsVersioning/EventsVersioning.Tests/SimpleMappings/NewRequiredProperty.cs @@ -10,43 +10,43 @@ public class NewRequiredProperty public enum ShoppingCartStatus { Pending = 1, - Initialized = 2, + Opened = 2, Confirmed = 3, Cancelled = 4 } - public record ShoppingCartInitialized( + public record ShoppingCartOpened( Guid ShoppingCartId, Guid ClientId, // Adding new not required property as nullable - ShoppingCartStatus Status = ShoppingCartStatus.Initialized + ShoppingCartStatus Status = ShoppingCartStatus.Opened ); [Fact] public void Should_BeForwardCompatible() { // Given - var oldEvent = new V1.ShoppingCartInitialized(Guid.NewGuid(), Guid.NewGuid()); + var oldEvent = new V1.ShoppingCartOpened(Guid.NewGuid(), Guid.NewGuid()); var json = JsonSerializer.Serialize(oldEvent); // When - var @event = JsonSerializer.Deserialize(json); + var @event = JsonSerializer.Deserialize(json); @event.Should().NotBeNull(); @event!.ShoppingCartId.Should().Be(oldEvent.ShoppingCartId); @event.ClientId.Should().Be(oldEvent.ClientId); - @event.Status.Should().Be(ShoppingCartStatus.Initialized); + @event.Status.Should().Be(ShoppingCartStatus.Opened); } [Fact] public void Should_BeBackwardCompatible() { // Given - var @event = new ShoppingCartInitialized(Guid.NewGuid(), Guid.NewGuid(), ShoppingCartStatus.Pending); + var @event = new ShoppingCartOpened(Guid.NewGuid(), Guid.NewGuid(), ShoppingCartStatus.Pending); var json = JsonSerializer.Serialize(@event); // When - var oldEvent = JsonSerializer.Deserialize(json); + var oldEvent = JsonSerializer.Deserialize(json); oldEvent.Should().NotBeNull(); oldEvent!.ShoppingCartId.Should().Be(@event.ShoppingCartId); diff --git a/Sample/EventsVersioning/EventsVersioning.Tests/SimpleMappings/RenamedProperty.cs b/Sample/EventsVersioning/EventsVersioning.Tests/SimpleMappings/RenamedProperty.cs index b450bf50f..21e95ca51 100644 --- a/Sample/EventsVersioning/EventsVersioning.Tests/SimpleMappings/RenamedProperty.cs +++ b/Sample/EventsVersioning/EventsVersioning.Tests/SimpleMappings/RenamedProperty.cs @@ -8,13 +8,13 @@ namespace EventsVersioning.Tests.SimpleMappings; public class RenamedProperty { - public class ShoppingCartInitialized + public class ShoppingCartOpened { [JsonPropertyName("ShoppingCartId")] public Guid CartId { get; init; } public Guid ClientId { get; init; } - public ShoppingCartInitialized( + public ShoppingCartOpened( Guid cartId, Guid clientId ) @@ -28,11 +28,11 @@ Guid clientId public void Should_BeForwardCompatible() { // Given - var oldEvent = new V1.ShoppingCartInitialized(Guid.NewGuid(), Guid.NewGuid()); + var oldEvent = new V1.ShoppingCartOpened(Guid.NewGuid(), Guid.NewGuid()); var json = JsonSerializer.Serialize(oldEvent); // When - var @event = JsonSerializer.Deserialize(json); + var @event = JsonSerializer.Deserialize(json); @event.Should().NotBeNull(); @event!.CartId.Should().Be(oldEvent.ShoppingCartId); @@ -43,11 +43,11 @@ public void Should_BeForwardCompatible() public void Should_BeBackwardCompatible() { // Given - var @event = new ShoppingCartInitialized(Guid.NewGuid(), Guid.NewGuid()); + var @event = new ShoppingCartOpened(Guid.NewGuid(), Guid.NewGuid()); var json = JsonSerializer.Serialize(@event); // When - var oldEvent = JsonSerializer.Deserialize(json); + var oldEvent = JsonSerializer.Deserialize(json); oldEvent.Should().NotBeNull(); oldEvent!.ShoppingCartId.Should().Be(@event.CartId); diff --git a/Sample/EventsVersioning/EventsVersioning.Tests/Transformations/MultipleTransformationsWithDifferentEventTypes.cs b/Sample/EventsVersioning/EventsVersioning.Tests/Transformations/MultipleTransformationsWithDifferentEventTypes.cs index a81f67ffa..c0f888862 100644 --- a/Sample/EventsVersioning/EventsVersioning.Tests/Transformations/MultipleTransformationsWithDifferentEventTypes.cs +++ b/Sample/EventsVersioning/EventsVersioning.Tests/Transformations/MultipleTransformationsWithDifferentEventTypes.cs @@ -12,7 +12,7 @@ public record Client( string Name = "Unknown" ); - public record ShoppingCartInitialized( + public record ShoppingCartOpened( Guid ShoppingCartId, Client Client ); @@ -20,7 +20,7 @@ Client Client public enum ShoppingCartStatus { Pending = 1, - Initialized = 2, + Opened = 2, Confirmed = 3, Cancelled = 4 } @@ -42,18 +42,18 @@ JsonDocument oldEventJson new Client( oldEvent.GetProperty("ClientId").GetGuid() ), - ShoppingCartStatus.Initialized + ShoppingCartStatus.Opened ); } public static ShoppingCartInitializedWithStatus UpcastV2( - ShoppingCartInitialized oldEvent + ShoppingCartOpened oldEvent ) { return new ShoppingCartInitializedWithStatus( oldEvent.ShoppingCartId, oldEvent.Client, - ShoppingCartStatus.Initialized + ShoppingCartStatus.Opened ); } @@ -149,15 +149,15 @@ public void UpcastObjects_Should_BeForwardCompatible() var transformations = new EventTransformations() .Register(eventTypeV1Name, UpcastV1) - .Register(eventTypeV2Name, UpcastV2); + .Register(eventTypeV2Name, UpcastV2); var serializer = new EventSerializer(mapping, transformations); - var eventV1 = new V1.ShoppingCartInitialized( + var eventV1 = new V1.ShoppingCartOpened( Guid.NewGuid(), Guid.NewGuid() ); - var eventV2 = new ShoppingCartInitialized( + var eventV2 = new ShoppingCartOpened( Guid.NewGuid(), new Client(Guid.NewGuid(), "Oscar the Grouch") ); @@ -187,11 +187,11 @@ public void UpcastObjects_Should_BeForwardCompatible() deserializedEvents[0].Client.Should().NotBeNull(); deserializedEvents[0].Client.Id.Should().Be(eventV1.ClientId); deserializedEvents[0].Client.Name.Should().Be("Unknown"); - deserializedEvents[0].Status.Should().Be(ShoppingCartStatus.Initialized); + deserializedEvents[0].Status.Should().Be(ShoppingCartStatus.Opened); deserializedEvents[1].ShoppingCartId.Should().Be(eventV2.ShoppingCartId); deserializedEvents[1].Client.Should().Be(eventV2.Client); - deserializedEvents[1].Status.Should().Be(ShoppingCartStatus.Initialized); + deserializedEvents[1].Status.Should().Be(ShoppingCartStatus.Opened); deserializedEvents[2].ShoppingCartId.Should().Be(eventV3.ShoppingCartId); deserializedEvents[2].Client.Should().Be(eventV3.Client); diff --git a/Sample/EventsVersioning/EventsVersioning.Tests/Transformations/StreamTransformations.cs b/Sample/EventsVersioning/EventsVersioning.Tests/Transformations/StreamTransformations.cs index 51ba5cb5a..5ba4ebdbb 100644 --- a/Sample/EventsVersioning/EventsVersioning.Tests/Transformations/StreamTransformations.cs +++ b/Sample/EventsVersioning/EventsVersioning.Tests/Transformations/StreamTransformations.cs @@ -27,9 +27,9 @@ public List FlattenInitializedEventsWithProductItemsAdded( List events ) { - var cartInitialized = events.First(); + var cartOpened = events.First(); var cartInitializedCorrelationId = - JsonSerializer.Deserialize(cartInitialized.MetaData)! + JsonSerializer.Deserialize(cartOpened.MetaData)! .CorrelationId; var i = 1; @@ -54,7 +54,7 @@ List events } var mergedEvent = ToShoppingCartInitializedWithProducts( - cartInitialized, + cartOpened, productItemsAdded ); @@ -231,7 +231,7 @@ public void UpcastObjects_Should_BeForwardCompatible() { ( "shopping_cart_initialized_v1", - new V1.ShoppingCartInitialized(shoppingCardId, clientId), + new V1.ShoppingCartOpened(shoppingCardId, clientId), new EventMetadata(theSameCorrelationId) ), ( diff --git a/Sample/EventsVersioning/EventsVersioning.Tests/Upcasters/ChangedStructure.cs b/Sample/EventsVersioning/EventsVersioning.Tests/Upcasters/ChangedStructure.cs index 6750728f8..50606b0cc 100644 --- a/Sample/EventsVersioning/EventsVersioning.Tests/Upcasters/ChangedStructure.cs +++ b/Sample/EventsVersioning/EventsVersioning.Tests/Upcasters/ChangedStructure.cs @@ -12,28 +12,28 @@ public record Client( string Name = "Unknown" ); - public record ShoppingCartInitialized( + public record ShoppingCartOpened( Guid ShoppingCartId, Client Client ); - public static ShoppingCartInitialized Upcast( - V1.ShoppingCartInitialized oldEvent + public static ShoppingCartOpened Upcast( + V1.ShoppingCartOpened oldEvent ) { - return new ShoppingCartInitialized( + return new ShoppingCartOpened( oldEvent.ShoppingCartId, new Client(oldEvent.ClientId) ); } - public static ShoppingCartInitialized Upcast( + public static ShoppingCartOpened Upcast( string oldEventJson ) { var oldEvent = JsonDocument.Parse(oldEventJson).RootElement; - return new ShoppingCartInitialized( + return new ShoppingCartOpened( oldEvent.GetProperty("ShoppingCartId").GetGuid(), new Client( oldEvent.GetProperty("ClientId").GetGuid() @@ -45,7 +45,7 @@ string oldEventJson public void UpcastObjects_Should_BeForwardCompatible() { // Given - var oldEvent = new V1.ShoppingCartInitialized(Guid.NewGuid(), Guid.NewGuid()); + var oldEvent = new V1.ShoppingCartOpened(Guid.NewGuid(), Guid.NewGuid()); // When var @event = Upcast(oldEvent); @@ -60,7 +60,7 @@ public void UpcastObjects_Should_BeForwardCompatible() public void UpcastJson_Should_BeForwardCompatible() { // Given - var oldEvent = new V1.ShoppingCartInitialized(Guid.NewGuid(), Guid.NewGuid()); + var oldEvent = new V1.ShoppingCartOpened(Guid.NewGuid(), Guid.NewGuid()); // When var @event = Upcast( diff --git a/Sample/EventsVersioning/EventsVersioning.Tests/Upcasters/NewRequiredPropertyFromMetadata.cs b/Sample/EventsVersioning/EventsVersioning.Tests/Upcasters/NewRequiredPropertyFromMetadata.cs index 1f47d9af8..1dfa324ac 100644 --- a/Sample/EventsVersioning/EventsVersioning.Tests/Upcasters/NewRequiredPropertyFromMetadata.cs +++ b/Sample/EventsVersioning/EventsVersioning.Tests/Upcasters/NewRequiredPropertyFromMetadata.cs @@ -11,25 +11,25 @@ public record EventMetadata( Guid UserId ); - public record ShoppingCartInitialized( + public record ShoppingCartOpened( Guid ShoppingCartId, Guid ClientId, Guid InitializedBy ); - public static ShoppingCartInitialized Upcast( - V1.ShoppingCartInitialized oldEvent, + public static ShoppingCartOpened Upcast( + V1.ShoppingCartOpened oldEvent, EventMetadata eventMetadata ) { - return new ShoppingCartInitialized( + return new ShoppingCartOpened( oldEvent.ShoppingCartId, oldEvent.ClientId, eventMetadata.UserId ); } - public static ShoppingCartInitialized Upcast( + public static ShoppingCartOpened Upcast( string oldEventJson, string eventMetadataJson ) @@ -37,7 +37,7 @@ string eventMetadataJson var oldEvent = JsonDocument.Parse(oldEventJson); var eventMetadata = JsonDocument.Parse(eventMetadataJson); - return new ShoppingCartInitialized( + return new ShoppingCartOpened( oldEvent.RootElement.GetProperty("ShoppingCartId").GetGuid(), oldEvent.RootElement.GetProperty("ClientId").GetGuid(), eventMetadata.RootElement.GetProperty("UserId").GetGuid() @@ -48,7 +48,7 @@ string eventMetadataJson public void UpcastObjects_Should_BeForwardCompatible() { // Given - var oldEvent = new V1.ShoppingCartInitialized(Guid.NewGuid(), Guid.NewGuid()); + var oldEvent = new V1.ShoppingCartOpened(Guid.NewGuid(), Guid.NewGuid()); var eventMetadata = new EventMetadata(Guid.NewGuid()); // When @@ -64,7 +64,7 @@ public void UpcastObjects_Should_BeForwardCompatible() public void UpcastJson_Should_BeForwardCompatible() { // Given - var oldEvent = new V1.ShoppingCartInitialized(Guid.NewGuid(), Guid.NewGuid()); + var oldEvent = new V1.ShoppingCartOpened(Guid.NewGuid(), Guid.NewGuid()); var eventMetadata = new EventMetadata(Guid.NewGuid()); // When diff --git a/Sample/EventsVersioning/README.md b/Sample/EventsVersioning/README.md index 7c8de17e4..10fa76dda 100644 --- a/Sample/EventsVersioning/README.md +++ b/Sample/EventsVersioning/README.md @@ -43,7 +43,7 @@ There are some simple mappings that we could handle on the code structure or ser Having event defined as such: ```csharp -public record ShoppingCartInitialized( +public record ShoppingCartOpened( Guid ShoppingCartId, Guid ClientId ); @@ -52,7 +52,7 @@ public record ShoppingCartInitialized( If we'd like to add a new not required property, e.g. `IntializedAt`, we can add it just as a new nullable property. The essential fact to decide if that's the right strategy is if we're good with not having it defined. It can be handled as: ```csharp -public record ShoppingCartInitialized( +public record ShoppingCartOpened( Guid ShoppingCartId, Guid ClientId, // Adding new not required property as nullable @@ -69,22 +69,22 @@ See full sample: [NewNotRequiredProperty.cs](./EventsVersioning.Tests/SimpleMapp We must define a default value if we'd like to add a new required property and make it non-breaking. It's the same as you'd add a new column to the relational table. -For instance, we decide that we'd like to add a validation step when the shopping cart is open (e.g. for fraud or spam detection), and our shopping cart can be opened with a pending state. We could solve that by adding the new property with the status information and setting it to `Initialized`, assuming that all old events were appended using the older logic. +For instance, we decide that we'd like to add a validation step when the shopping cart is open (e.g. for fraud or spam detection), and our shopping cart can be opened with a pending state. We could solve that by adding the new property with the status information and setting it to `Opened`, assuming that all old events were appended using the older logic. ```csharp public enum ShoppingCartStatus { Pending = 1, - Initialized = 2, + Opened = 2, Confirmed = 3, Cancelled = 4 } -public record ShoppingCartInitialized( +public record ShoppingCartOpened( Guid ShoppingCartId, Guid ClientId, // Adding new not required property as nullable - ShoppingCartStatus Status = ShoppingCartStatus.Initialized + ShoppingCartStatus Status = ShoppingCartStatus.Opened ); ``` @@ -99,13 +99,13 @@ Let's assume that we concluded that keeping `ShoppingCart` prefix in the `Shoppi We could do it as: ```csharp -public class ShoppingCartInitialized +public class ShoppingCartOpened { [JsonPropertyName("ShoppingCartId")] public Guid CartId { get; init; } public Guid ClientId { get; init; } - public ShoppingCartInitialized( + public ShoppingCartOpened( Guid cartId, Guid clientId ) @@ -156,7 +156,7 @@ public record Client( string Name = "Unknown" ); -public record ShoppingCartInitialized( +public record ShoppingCartOpened( Guid ShoppingCartId, Client Client ); @@ -167,11 +167,11 @@ We can define upcaster as a function that'll later plug in the deserialisation p We can define the transformation of the object of the old structure as: ```csharp -public static ShoppingCartInitialized Upcast( - V1.ShoppingCartInitialized oldEvent +public static ShoppingCartOpened Upcast( + V1.ShoppingCartOpened oldEvent ) { - return new ShoppingCartInitialized( + return new ShoppingCartOpened( oldEvent.ShoppingCartId, new Client(oldEvent.ClientId) ); @@ -181,13 +181,13 @@ public static ShoppingCartInitialized Upcast( Or we can map it from JSON ```csharp -public static ShoppingCartInitialized Upcast( +public static ShoppingCartOpened Upcast( string oldEventJson ) { var oldEvent = JsonDocument.Parse(oldEventJson).RootElement; - return new ShoppingCartInitialized( + return new ShoppingCartOpened( oldEvent.GetProperty("ShoppingCartId").GetGuid(), new Client( oldEvent.GetProperty("ClientId").GetGuid() @@ -209,7 +209,7 @@ public record EventMetadata( Guid UserId ); -public record ShoppingCartInitialized( +public record ShoppingCartOpened( Guid ShoppingCartId, Guid ClientId, Guid InitializedBy @@ -219,12 +219,12 @@ public record ShoppingCartInitialized( Upcaster from old object to the new one can look like: ```csharp -public static ShoppingCartInitialized Upcast( - V1.ShoppingCartInitialized oldEvent, +public static ShoppingCartOpened Upcast( + V1.ShoppingCartOpened oldEvent, EventMetadata eventMetadata ) { - return new ShoppingCartInitialized( + return new ShoppingCartOpened( oldEvent.ShoppingCartId, oldEvent.ClientId, eventMetadata.UserId @@ -235,7 +235,7 @@ public static ShoppingCartInitialized Upcast( From JSON to the object: ```csharp -public static ShoppingCartInitialized Upcast( +public static ShoppingCartOpened Upcast( string oldEventJson, string eventMetadataJson ) @@ -243,7 +243,7 @@ public static ShoppingCartInitialized Upcast( var oldEvent = JsonDocument.Parse(oldEventJson); var eventMetadata = JsonDocument.Parse(eventMetadataJson); - return new ShoppingCartInitialized( + return new ShoppingCartOpened( oldEvent.RootElement.GetProperty("ShoppingCartId").GetGuid(), oldEvent.RootElement.GetProperty("ClientId").GetGuid(), eventMetadata.RootElement.GetProperty("UserId").GetGuid() @@ -260,11 +260,11 @@ In the same way, as described above, we can downcast the events from the new str From the new object to the old one: ```csharp -public static V1.ShoppingCartInitialized Downcast( - ShoppingCartInitialized newEvent +public static V1.ShoppingCartOpened Downcast( + ShoppingCartOpened newEvent ) { - return new V1.ShoppingCartInitialized( + return new V1.ShoppingCartOpened( newEvent.ShoppingCartId, newEvent.Client.Id ); @@ -274,13 +274,13 @@ public static V1.ShoppingCartInitialized Downcast( From new JSON format to the old object: ```csharp -public static V1.ShoppingCartInitialized Downcast( +public static V1.ShoppingCartOpened Downcast( string newEventJson ) { var newEvent = JsonDocument.Parse(newEventJson).RootElement; - return new V1.ShoppingCartInitialized( + return new V1.ShoppingCartOpened( newEvent.GetProperty("ShoppingCartId").GetGuid(), newEvent.GetProperty("Client").GetProperty("Id").GetGuid() ); @@ -340,7 +340,7 @@ We have two `Register` methods. Both of them has JSON and handler function as pa ```csharp var transformations = new EventTransformations() .Register(eventTypeV1Name, UpcastV1) - .Register( + .Register( eventTypeV2Name, UpcastV2); ``` @@ -416,7 +416,7 @@ See a full sample in [MultipleTransformationsWithDifferentEventTypes.cs](./Event You might want not only to transform a single event into another (1:1) but also a set of events into another one (N:M). -Let's take as an example scenario where we can initialise not only empty shopping cart but also filled with products. For some time, we were doing that by publishing multiple events: `ShoppingCartInitialized` and `ProductItemAddedToShoppingCart` for each added product item. We decided that we'd like to replace this with event containing list of product items: +Let's take as an example scenario where we can initialise not only empty shopping cart but also filled with products. For some time, we were doing that by publishing multiple events: `ShoppingCartOpened` and `ProductItemAddedToShoppingCart` for each added product item. We decided that we'd like to replace this with event containing list of product items: ```csharp public record ProductItem( @@ -429,7 +429,7 @@ public record PricedProductItem( decimal UnitPrice ); -public record ShoppingCartInitialized( +public record ShoppingCartOpened( Guid ShoppingCartId, Guid ClientId ); @@ -520,9 +520,9 @@ public List FlattenInitializedEventsWithProductItemsAdded( List events ) { - var cartInitialized = events.First(); + var cartOpened = events.First(); var cartInitializedCorrelationId = - JsonSerializer.Deserialize(cartInitialized.MetaData)! + JsonSerializer.Deserialize(cartOpened.MetaData)! .CorrelationId; var i = 1; @@ -547,7 +547,7 @@ public List FlattenInitializedEventsWithProductItemsAdded( } var mergedEvent = ToShoppingCartInitializedWithProducts( - cartInitialized, + cartOpened, productItemsAdded ); From f31ebf425626e4d0e2f61a352b644482f7c403c4 Mon Sep 17 00:00:00 2001 From: Oskar Dudycz Date: Sat, 12 Mar 2022 10:10:54 +0100 Subject: [PATCH 2/3] Renamed StreamEvent Extensions to EventEnvelopeExtensions --- .../{StreamEventExtensions.cs => EventEnvelopeExtensions.cs} | 4 ++-- .../Subscriptions/EventStoreDBSubscriptionToAll.cs | 2 +- Core.Marten/Config.cs | 4 ++-- .../ShoppingCarts/Canceling/CancelShoppingCartTests.cs | 2 +- .../ShoppingCarts/Canceling/CancelShoppingCartTests.cs | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) rename Core.EventStoreDB/Events/{StreamEventExtensions.cs => EventEnvelopeExtensions.cs} (85%) diff --git a/Core.EventStoreDB/Events/StreamEventExtensions.cs b/Core.EventStoreDB/Events/EventEnvelopeExtensions.cs similarity index 85% rename from Core.EventStoreDB/Events/StreamEventExtensions.cs rename to Core.EventStoreDB/Events/EventEnvelopeExtensions.cs index ea18d1e8a..2db7944c8 100644 --- a/Core.EventStoreDB/Events/StreamEventExtensions.cs +++ b/Core.EventStoreDB/Events/EventEnvelopeExtensions.cs @@ -4,9 +4,9 @@ namespace Core.EventStoreDB.Events; -public static class StreamEventExtensions +public static class EventEnvelopeExtensions { - public static EventEnvelope? ToStreamEvent(this ResolvedEvent resolvedEvent) + public static EventEnvelope? ToEventEnvelope(this ResolvedEvent resolvedEvent) { var eventData = resolvedEvent.Deserialize(); var eventMetadata = resolvedEvent.DeserializeMetadata(); diff --git a/Core.EventStoreDB/Subscriptions/EventStoreDBSubscriptionToAll.cs b/Core.EventStoreDB/Subscriptions/EventStoreDBSubscriptionToAll.cs index 2df38691b..38f7637c9 100644 --- a/Core.EventStoreDB/Subscriptions/EventStoreDBSubscriptionToAll.cs +++ b/Core.EventStoreDB/Subscriptions/EventStoreDBSubscriptionToAll.cs @@ -77,7 +77,7 @@ private async Task HandleEvent(StreamSubscription subscription, ResolvedEvent re { if (IsEventWithEmptyData(resolvedEvent) || IsCheckpointEvent(resolvedEvent)) return; - var streamEvent = resolvedEvent.ToStreamEvent(); + var streamEvent = resolvedEvent.ToEventEnvelope(); if (streamEvent == null) { diff --git a/Core.Marten/Config.cs b/Core.Marten/Config.cs index 5e0f35490..3c85e5534 100644 --- a/Core.Marten/Config.cs +++ b/Core.Marten/Config.cs @@ -79,14 +79,14 @@ private static StoreOptions SetStoreOptions( "MartenSubscription" ); - configureOptions?.Invoke(options); - if (config.UseMetadata) { options.Events.MetadataConfig.CausationIdEnabled = true; options.Events.MetadataConfig.CorrelationIdEnabled = true; } + configureOptions?.Invoke(options); + return options; } } diff --git a/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Canceling/CancelShoppingCartTests.cs b/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Canceling/CancelShoppingCartTests.cs index 1961d28a9..540bfd12d 100644 --- a/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Canceling/CancelShoppingCartTests.cs +++ b/Sample/EventStoreDB/ECommerce/Carts/Carts.Api.Tests/ShoppingCarts/Canceling/CancelShoppingCartTests.cs @@ -67,7 +67,7 @@ public async Task Put_Should_Confirm_ShoppingCart() var cartDetails = await queryResponse.GetResultFromJson(); cartDetails.Should().NotBeNull(); cartDetails.Id.Should().Be(fixture.ShoppingCartId); - cartDetails.Status.Should().Be(ShoppingCartStatus.Confirmed); + cartDetails.Status.Should().Be(ShoppingCartStatus.Canceled); cartDetails.ClientId.Should().Be(fixture.ClientId); cartDetails.Version.Should().Be(1); } diff --git a/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/Canceling/CancelShoppingCartTests.cs b/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/Canceling/CancelShoppingCartTests.cs index 658ce77b7..11734bccd 100644 --- a/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/Canceling/CancelShoppingCartTests.cs +++ b/Sample/EventStoreDB/Simple/ECommerce.Api.Tests/ShoppingCarts/Canceling/CancelShoppingCartTests.cs @@ -67,7 +67,7 @@ public async Task Put_Should_Confirm_ShoppingCart() var cartDetails = await queryResponse.GetResultFromJson(); cartDetails.Should().NotBeNull(); cartDetails.Id.Should().Be(fixture.ShoppingCartId); - cartDetails.Status.Should().Be(ShoppingCartStatus.Confirmed); + cartDetails.Status.Should().Be(ShoppingCartStatus.Canceled); cartDetails.ClientId.Should().Be(fixture.ClientId); cartDetails.Version.Should().Be(1); } From 8fd6afa87f1045b31fce9763ad5a4c7a7566e1b4 Mon Sep 17 00:00:00 2001 From: Oskar Dudycz Date: Sat, 12 Mar 2022 13:25:27 +0100 Subject: [PATCH 3/3] Fixed Canceling ShoppingCart in Marten ECommerce example --- .../ExceptionHandling/ExceptionHandlingMiddleware.cs | 7 +++++-- .../ShoppingCarts/CancelingCart/CancelShoppingCart.cs | 2 +- Sample/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCart.cs | 1 + 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Core.WebApi/Middlewares/ExceptionHandling/ExceptionHandlingMiddleware.cs b/Core.WebApi/Middlewares/ExceptionHandling/ExceptionHandlingMiddleware.cs index 7c9a40e19..b1079d325 100644 --- a/Core.WebApi/Middlewares/ExceptionHandling/ExceptionHandlingMiddleware.cs +++ b/Core.WebApi/Middlewares/ExceptionHandling/ExceptionHandlingMiddleware.cs @@ -36,7 +36,10 @@ public async Task Invoke(HttpContext context /* other scoped dependencies */) private Task HandleExceptionAsync(HttpContext context, Exception exception) { logger.LogError(exception, exception.Message); - Console.WriteLine(exception.Message); + Console.WriteLine("ERROR:" + exception.Message + exception.StackTrace); + + if(exception.InnerException != null) + Console.WriteLine("INNER DETAILS:" + exception.InnerException.Message + exception.InnerException.StackTrace); var codeInfo = ExceptionToHttpStatusMapper.Map(exception); @@ -70,4 +73,4 @@ public static IApplicationBuilder UseExceptionHandlingMiddleware( ExceptionToHttpStatusMapper.CustomMap = customMap; return app.UseMiddleware(); } -} \ No newline at end of file +} diff --git a/Sample/ECommerce/Carts/Carts/ShoppingCarts/CancelingCart/CancelShoppingCart.cs b/Sample/ECommerce/Carts/Carts/ShoppingCarts/CancelingCart/CancelShoppingCart.cs index 17fcde6e8..85286b867 100644 --- a/Sample/ECommerce/Carts/Carts/ShoppingCarts/CancelingCart/CancelShoppingCart.cs +++ b/Sample/ECommerce/Carts/Carts/ShoppingCarts/CancelingCart/CancelShoppingCart.cs @@ -38,7 +38,7 @@ public async Task Handle(CancelShoppingCart command, CancellationToken can await scope.Do((expectedVersion, traceMetadata) => cartRepository.GetAndUpdate( command.CartId, - cart => cart.Confirm(), + cart => cart.Cancel(), expectedVersion, traceMetadata, cancellationToken diff --git a/Sample/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCart.cs b/Sample/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCart.cs index c3209534d..0a30a16d5 100644 --- a/Sample/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCart.cs +++ b/Sample/ECommerce/Carts/Carts/ShoppingCarts/ShoppingCart.cs @@ -49,6 +49,7 @@ public void Apply(ShoppingCartOpened @event) Id = @event.CartId; ClientId = @event.ClientId; ProductItems = new List(); + Status = ShoppingCartStatus.Pending; } public void AddProduct(