diff --git a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs index 4dd1143f6..2ab4ccb7f 100644 --- a/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs +++ b/src/Services/Catalog/Catalog.API/Controllers/CatalogController.cs @@ -216,7 +216,9 @@ public class CatalogController : ControllerBase } var oldPrice = catalogItem.Price; + var oldStock = catalogItem.AvailableStock; var raiseProductPriceChangedEvent = oldPrice != productToUpdate.Price; + var raiseProductStockChangedEvent = oldStock != productToUpdate.AvailableStock; // Update current product catalogItem = productToUpdate; @@ -233,6 +235,18 @@ public class CatalogController : ControllerBase // Publish through the Event Bus and mark the saved event as published await _catalogIntegrationEventService.PublishThroughEventBusAsync(priceChangedEvent); } + else if (raiseProductStockChangedEvent) + { + // Create Integration Event to be published through the Event Bus + var stockChangedEvent = new ProductStockChangedIntegrationEvent(catalogItem.Id, productToUpdate.AvailableStock, oldStock); + + // Achieving atomicity between original Catalog database operation and the IntegrationEventLog thanks to a local transaction + await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(stockChangedEvent); + + // Publish through the Event Bus and mark the saved event as published + await _catalogIntegrationEventService.PublishThroughEventBusAsync(stockChangedEvent); + + } else // Just save the updated product because the Product's Price hasn't changed. { await _catalogContext.SaveChangesAsync(); @@ -261,6 +275,26 @@ public class CatalogController : ControllerBase await _catalogContext.SaveChangesAsync(); + // publish CatalogItemCreatedIntegrationEvent + var productCreatedEvent = new ProductCreatedIntegrationEvent() + { + AvailableStock = item.AvailableStock, + CatalogBrand = item.CatalogBrand, + CatalogBrandId = item.CatalogBrandId, + CatalogType = item.CatalogType, + CatalogTypeId = item.CatalogTypeId, + Description = item.Description, + Id = item.Id, + MaxStockThreshold = item.MaxStockThreshold, + Name = item.Name, + OnReorder = item.OnReorder + }; + // Achieving atomicity between original Catalog database operation and the IntegrationEventLog thanks to a local transaction + await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(productCreatedEvent); + + // Publish through the Event Bus and mark the saved event as published + await _catalogIntegrationEventService.PublishThroughEventBusAsync(productCreatedEvent); + return CreatedAtAction(nameof(ItemByIdAsync), new { id = item.Id }, null); } @@ -282,6 +316,13 @@ public class CatalogController : ControllerBase await _catalogContext.SaveChangesAsync(); + var productDeletedEvent = new ProductDeletedIntegrationEvent(product.Id); + // Achieving atomicity between original Catalog database operation and the IntegrationEventLog thanks to a local transaction + await _catalogIntegrationEventService.SaveEventAndCatalogContextChangesAsync(productDeletedEvent); + + // Publish through the Event Bus and mark the saved event as published + await _catalogIntegrationEventService.PublishThroughEventBusAsync(productDeletedEvent); + return NoContent(); } diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductCreatedIntegrationEvent.cs b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductCreatedIntegrationEvent.cs new file mode 100644 index 000000000..a670da604 --- /dev/null +++ b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductCreatedIntegrationEvent.cs @@ -0,0 +1,39 @@ +namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events; + +public record ProductCreatedIntegrationEvent : IntegrationEvent +{ + public int Id { get; set; } + + public string Name { get; set; } + + public string Description { get; set; } + + public decimal Price { get; set; } + + public string PictureFileName { get; set; } + + public string PictureUri { get; set; } + + public int CatalogTypeId { get; set; } + + public CatalogType CatalogType { get; set; } + + public int CatalogBrandId { get; set; } + + public CatalogBrand CatalogBrand { get; set; } + + // Quantity in stock + public int AvailableStock { get; set; } + + // Available stock at which we should reorder + public int RestockThreshold { get; set; } + + + // Maximum number of units that can be in-stock at any time (due to physicial/logistical constraints in warehouses) + public int MaxStockThreshold { get; set; } + + /// + /// True if item is on reorder + /// + public bool OnReorder { get; set; } +} \ No newline at end of file diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductDeletedIntegrationEvent.cs b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductDeletedIntegrationEvent.cs new file mode 100644 index 000000000..09bc2d383 --- /dev/null +++ b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductDeletedIntegrationEvent.cs @@ -0,0 +1,11 @@ +namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events; + +public record ProductDeletedIntegrationEvent : IntegrationEvent +{ + public int ProductId { get; private init; } + + public ProductDeletedIntegrationEvent(int productId) + { + ProductId = productId; + } +} \ No newline at end of file diff --git a/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductStockChangedIntegrationEvent.cs b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductStockChangedIntegrationEvent.cs new file mode 100644 index 000000000..c64f24761 --- /dev/null +++ b/src/Services/Catalog/Catalog.API/IntegrationEvents/Events/ProductStockChangedIntegrationEvent.cs @@ -0,0 +1,20 @@ +namespace Microsoft.eShopOnContainers.Services.Catalog.API.IntegrationEvents.Events; + +// Integration Events notes: +// An Event is “something that has happened in the past”, therefore its name has to be past tense +// An Integration Event is an event that can cause side effects to other microservices, Bounded-Contexts or external systems. +public record ProductStockChangedIntegrationEvent : IntegrationEvent +{ + public int ProductId { get; private init; } + + public decimal NewStock { get; private init; } + + public decimal OldStock { get; private init; } + + public ProductStockChangedIntegrationEvent(int productId, decimal newStock, decimal oldStock) + { + ProductId = productId; + NewStock = newStock; + OldStock = oldStock; + } +} \ No newline at end of file