diff --git a/src/Catalog/Catalog.Api/Catalog.Api.Offers.http b/src/Catalog/Catalog.Api/Catalog.Api.Offers.http new file mode 100644 index 0000000..0ed40e5 --- /dev/null +++ b/src/Catalog/Catalog.Api/Catalog.Api.Offers.http @@ -0,0 +1,46 @@ +# curl -X 'GET' +# 'http://localhost:5252/offers/0190421a-1466-4f1b-8261-a22a528aadae' +# -H 'accept: text/plain' +GET http://localhost:5252/offers/0190421a-1466-4f1b-8261-a22a528aadae +accept: text/plain + +### + +# curl -X 'POST' +# 'http://localhost:5252/offer/draft' +# -H 'accept: text/plain' +# -H 'Content-Type: application/json' +# -d '{ +# "sku": "36606-001", +# "createdBy": "erik" +#}' +POST http://localhost:5252/offer/draft +accept: text/plain +Content-Type: application/json + +{ + "sku": "36606-001", + "createdBy": "erik" +} + +### + +# curl -X 'POST' +# 'http://localhost:5252/offer/activate' +# -H 'accept: text/plain' +# -H 'Content-Type: application/json' +# -d '{ +# "offerId": "0190421a-1466-4f1b-8261-a22a528aada", +# "activatedBy": "erik" +#}' +POST http://localhost:5252/offer/activate +accept: text/plain +Content-Type: application/json + +{ + "offerId": "0190421a-1466-4f1b-8261-a22a528aadae", + "activatedBy": "erik" +} + +### + diff --git a/src/Catalog/Catalog.Api/Commands/Offers/OfferCommandService.cs b/src/Catalog/Catalog.Api/Commands/Offers/OfferCommandService.cs new file mode 100644 index 0000000..4ef95a3 --- /dev/null +++ b/src/Catalog/Catalog.Api/Commands/Offers/OfferCommandService.cs @@ -0,0 +1,33 @@ +using Catalog.Offers; +using Ecommerce.Core.Identities; +using Eventuous; +using MongoDB.Bson.Serialization; + +namespace Catalog.Api.Commands.Offers; + +public class OfferCommandService : CommandService +{ + [Obsolete("Obsolete usage of OnNewAsync per Eventuous; use new API instead (TODO)")] + public OfferCommandService( + IAggregateStore store, + Services.IsSkuAvailable isSkuAvailable, + Services.IsUserAuthorized isUserAuthorized, + ICombIdGenerator idGenerator) + : base(store) + { + var generatedId = idGenerator.New(); + OnNewAsync(cmd => new OfferId(generatedId), + ((offer, cmd, _) => offer.Draft( + generatedId, + cmd.Sku, + DateTimeOffset.Now, + cmd.CreatedBy, + isSkuAvailable, + isUserAuthorized))); + + OnExisting(cmd => new OfferId(cmd.OfferId), + ((offer, cmd) => offer.Activate( + DateTimeOffset.Now, + cmd.ActivatedBy))); + } +} diff --git a/src/Catalog/Catalog.Api/Commands/Offers/OfferCommands.cs b/src/Catalog/Catalog.Api/Commands/Offers/OfferCommands.cs new file mode 100644 index 0000000..5169ca8 --- /dev/null +++ b/src/Catalog/Catalog.Api/Commands/Offers/OfferCommands.cs @@ -0,0 +1,14 @@ +namespace Catalog.Api.Commands.Offers; + +public class OfferCommands +{ + public record Draft( + string Sku, + string CreatedBy + ); + + public record Activate( + string OfferId, + string ActivatedBy + ); +} diff --git a/src/Catalog/Catalog.Api/Commands/PriceCommandService.cs b/src/Catalog/Catalog.Api/Commands/Prices/PriceCommandService.cs similarity index 97% rename from src/Catalog/Catalog.Api/Commands/PriceCommandService.cs rename to src/Catalog/Catalog.Api/Commands/Prices/PriceCommandService.cs index 6345224..159fcf9 100644 --- a/src/Catalog/Catalog.Api/Commands/PriceCommandService.cs +++ b/src/Catalog/Catalog.Api/Commands/Prices/PriceCommandService.cs @@ -2,7 +2,7 @@ using Ecommerce.Core.Identities; using Eventuous; -namespace Catalog.Api.Commands; +namespace Catalog.Api.Commands.Prices; public class PriceCommandService : CommandService { diff --git a/src/Catalog/Catalog.Api/Commands/PriceCommands.cs b/src/Catalog/Catalog.Api/Commands/Prices/PriceCommands.cs similarity index 93% rename from src/Catalog/Catalog.Api/Commands/PriceCommands.cs rename to src/Catalog/Catalog.Api/Commands/Prices/PriceCommands.cs index 9e20656..9dbefbb 100644 --- a/src/Catalog/Catalog.Api/Commands/PriceCommands.cs +++ b/src/Catalog/Catalog.Api/Commands/Prices/PriceCommands.cs @@ -1,4 +1,4 @@ -namespace Catalog.Api.Commands; +namespace Catalog.Api.Commands.Prices; public static class PriceCommands { diff --git a/src/Catalog/Catalog.Api/Commands/ProductCommandService.cs b/src/Catalog/Catalog.Api/Commands/Products/ProductCommandService.cs similarity index 74% rename from src/Catalog/Catalog.Api/Commands/ProductCommandService.cs rename to src/Catalog/Catalog.Api/Commands/Products/ProductCommandService.cs index 5747ae6..a30db6b 100644 --- a/src/Catalog/Catalog.Api/Commands/ProductCommandService.cs +++ b/src/Catalog/Catalog.Api/Commands/Products/ProductCommandService.cs @@ -1,9 +1,8 @@ using Catalog.Products; using Ecommerce.Core.Identities; using Eventuous; -using static Catalog.Api.Commands.ProductCommands; -namespace Catalog.Api.Commands; +namespace Catalog.Api.Commands.Products; public class ProductCommandService : CommandService { @@ -17,7 +16,7 @@ public ProductCommandService( { // On(); // TODO use new API instead of obsolete versions - OnNewAsync(cmd => new ProductId(cmd.ProductId), + OnNewAsync(cmd => new ProductId(cmd.ProductId), ((product, cmd, _) => product.Draft( cmd.ProductId, cmd.Sku, @@ -31,7 +30,7 @@ public ProductCommandService( isUserAuthorized))); var generatedId = idGenerator.New(); - OnNewAsync(cmd => new ProductId(generatedId), + OnNewAsync(cmd => new ProductId(generatedId), ((product, cmd, _) => product.Draft( generatedId, cmd.Sku, @@ -44,48 +43,48 @@ public ProductCommandService( isSkuAvailable, isUserAuthorized))); - OnExisting(cmd => new ProductId(cmd.ProductId), + OnExisting(cmd => new ProductId(cmd.ProductId), ((product, cmd) => product.Activate( DateTimeOffset.Now, cmd.ActivatedBy))); - OnExisting(cmd => new ProductId(cmd.ProductId), + OnExisting(cmd => new ProductId(cmd.ProductId), ((product, cmd) => product.Archive( DateTimeOffset.Now, cmd.ArchivedBy, cmd.Reason))); - OnExisting(cmd => new ProductId(cmd.ProductId), + OnExisting(cmd => new ProductId(cmd.ProductId), ((product, cmd) => product.CancelDraft( DateTimeOffset.Now, cmd.CancelledBy, cmd.Reason))); - OnExisting(cmd => new ProductId(cmd.ProductId), + OnExisting(cmd => new ProductId(cmd.ProductId), ((product, cmd) => product.AdjustDescription( cmd.Description, DateTimeOffset.Now, cmd.AdjustedBy))); - OnExisting(cmd => new ProductId(cmd.ProductId), + OnExisting(cmd => new ProductId(cmd.ProductId), ((product, cmd) => product.AdjustName( cmd.Name, DateTimeOffset.Now, cmd.AdjustedBy))); - OnExisting(cmd => new ProductId(cmd.ProductId), + OnExisting(cmd => new ProductId(cmd.ProductId), ((product, cmd) => product.AdjustBrand( cmd.Brand, DateTimeOffset.Now, cmd.AdjustedBy))); - OnExisting(cmd => new ProductId(cmd.ProductId), + OnExisting(cmd => new ProductId(cmd.ProductId), ((product, cmd) => product.TakeMeasurement( Measurement.GetName(cmd.Type), // TODO evaluate if this is a good path to take cmd.Unit, cmd.Value))); - OnExisting(cmd => new ProductId(cmd.ProductId), + OnExisting(cmd => new ProductId(cmd.ProductId), ((product, cmd) => product.RemoveMeasurement( Measurement.GetName(cmd.Type)))); // TODO evaluate if this is a good path to take; } diff --git a/src/Catalog/Catalog.Api/Commands/ProductCommands.cs b/src/Catalog/Catalog.Api/Commands/Products/ProductCommands.cs similarity index 96% rename from src/Catalog/Catalog.Api/Commands/ProductCommands.cs rename to src/Catalog/Catalog.Api/Commands/Products/ProductCommands.cs index c6aadec..2cbbda8 100644 --- a/src/Catalog/Catalog.Api/Commands/ProductCommands.cs +++ b/src/Catalog/Catalog.Api/Commands/Products/ProductCommands.cs @@ -1,4 +1,4 @@ -namespace Catalog.Api.Commands; +namespace Catalog.Api.Commands.Products; public static class ProductCommands { diff --git a/src/Catalog/Catalog.Api/HttpApi/Offers/OfferCommandApi.cs b/src/Catalog/Catalog.Api/HttpApi/Offers/OfferCommandApi.cs new file mode 100644 index 0000000..642ec09 --- /dev/null +++ b/src/Catalog/Catalog.Api/HttpApi/Offers/OfferCommandApi.cs @@ -0,0 +1,21 @@ +using Catalog.Api.Commands.Offers; +using Catalog.Offers; +using Eventuous; +using Eventuous.AspNetCore.Web; +using Microsoft.AspNetCore.Mvc; + +namespace Catalog.Api.HttpApi.Offers; + +[Route("/offer")] +public class OfferCommandApi(ICommandService service) : CommandHttpApiBase(service) +{ + [HttpPost] + [Route("draft")] + public Task> Draft([FromBody] OfferCommands.Draft cmd, CancellationToken ct) + => Handle(cmd, ct); + + [HttpPost] + [Route("activate")] + public Task> Activate([FromBody] OfferCommands.Activate cmd, CancellationToken ct) + => Handle(cmd, ct); +} diff --git a/src/Catalog/Catalog.Api/HttpApi/Offers/OfferQueryApi.cs b/src/Catalog/Catalog.Api/HttpApi/Offers/OfferQueryApi.cs new file mode 100644 index 0000000..13de686 --- /dev/null +++ b/src/Catalog/Catalog.Api/HttpApi/Offers/OfferQueryApi.cs @@ -0,0 +1,21 @@ +using Catalog.Offers; +using Eventuous; +using Microsoft.AspNetCore.Mvc; + +namespace Catalog.Api.HttpApi.Offers; + +[Route("/offers")] +public class OfferQueryApi : ControllerBase +{ + private readonly IAggregateStore _store; + + public OfferQueryApi(IAggregateStore store) => _store = store; + + [HttpGet] + [Route("{id}")] + public async Task GetProduct(string id, CancellationToken ct) + { + var product = await _store.Load(StreamName.For(id), ct); + return product.State; + } +} diff --git a/src/Catalog/Catalog.Api/HttpApi/Prices/PriceCommandApi.cs b/src/Catalog/Catalog.Api/HttpApi/Prices/PriceCommandApi.cs index 95b0b64..c91a833 100644 --- a/src/Catalog/Catalog.Api/HttpApi/Prices/PriceCommandApi.cs +++ b/src/Catalog/Catalog.Api/HttpApi/Prices/PriceCommandApi.cs @@ -1,4 +1,4 @@ -using Catalog.Api.Commands; +using Catalog.Api.Commands.Prices; using Catalog.Prices; using Eventuous; using Eventuous.AspNetCore.Web; diff --git a/src/Catalog/Catalog.Api/HttpApi/Products/ProductCommandApi.cs b/src/Catalog/Catalog.Api/HttpApi/Products/ProductCommandApi.cs index eca16b1..282aa81 100644 --- a/src/Catalog/Catalog.Api/HttpApi/Products/ProductCommandApi.cs +++ b/src/Catalog/Catalog.Api/HttpApi/Products/ProductCommandApi.cs @@ -1,4 +1,4 @@ -using Catalog.Api.Commands; +using Catalog.Api.Commands.Products; using Catalog.Products; using Eventuous; using Eventuous.AspNetCore.Web; diff --git a/src/Catalog/Catalog.Api/Registrations.cs b/src/Catalog/Catalog.Api/Registrations.cs index 04473a3..8606ace 100644 --- a/src/Catalog/Catalog.Api/Registrations.cs +++ b/src/Catalog/Catalog.Api/Registrations.cs @@ -1,7 +1,10 @@ using System.Text.Json; -using Catalog.Api.Commands; +using Catalog.Api.Commands.Offers; +using Catalog.Api.Commands.Prices; +using Catalog.Api.Commands.Products; using Catalog.Api.Infrastructure; using Catalog.Api.Queries; +using Catalog.Offers; using Catalog.Prices; using Catalog.Products; using Ecommerce.Core.Identities; @@ -41,6 +44,7 @@ public static void AddEventuous(this IServiceCollection services, IConfiguration // command services services.AddCommandService(); services.AddCommandService(); + services.AddCommandService(); // other internal and core services services.AddSingleton(); @@ -48,6 +52,8 @@ public static void AddEventuous(this IServiceCollection services, IConfiguration services.AddSingleton(id => new ValueTask(true)); services.AddSingleton(id => new ValueTask(true)); services.AddSingleton(id => new ValueTask(true)); + services.AddSingleton(id => new ValueTask(true)); + services.AddSingleton(id => new ValueTask(true)); // event store related services