Newer
Older
EventSourcingSnapshots / WarehouseProduct.cs
@Derek Comartin Derek Comartin on 2 Mar 2021 3 KB Fix bugs with interval
using System;
using System.Collections.Generic;

namespace EventSourcing.Demo
{
    public class WarehouseProductState
    {
        public int QuantityOnHand { get; set; }
    }

    public class WarehouseProduct
    {
        public string Sku { get; }
        private readonly IList<IEvent> _allEvents = new List<IEvent>();
        private readonly IList<IEvent> _uncommittedEvents = new List<IEvent>();

        // Projection (Current State)
        private readonly WarehouseProductState _warehouseProductState;

        public WarehouseProduct(string sku, WarehouseProductState state)
        {
            Sku = sku;
            _warehouseProductState = state;
        }

        public WarehouseProductState GetState()
        {
            return _warehouseProductState;
        }

        public void ShipProduct(int quantity)
        {
            if (quantity > _warehouseProductState.QuantityOnHand)
            {
                throw new InvalidDomainException("Ah... we don't have enough product to ship?");
            }

            AddEvent(new ProductShipped(Sku, quantity, DateTime.UtcNow));
        }

        public void ReceiveProduct(int quantity)
        {
            AddEvent(new ProductReceived(Sku, quantity, DateTime.UtcNow));
        }

        public void AdjustInventory(int quantity, string reason)
        {
            if (_warehouseProductState.QuantityOnHand + quantity < 0)
            {
                throw new InvalidDomainException("Cannot adjust to a negative quantity on hand.");
            }

            AddEvent(new InventoryAdjusted(Sku, quantity, reason, DateTime.UtcNow));
        }

        private void Apply(ProductShipped evnt)
        {
            _warehouseProductState.QuantityOnHand -= evnt.Quantity;
        }

        private void Apply(ProductReceived evnt)
        {
            _warehouseProductState.QuantityOnHand += evnt.Quantity;
        }

        private void Apply(InventoryAdjusted evnt)
        {
            _warehouseProductState.QuantityOnHand += evnt.Quantity;
        }

        public void ApplyEvent(IEvent evnt)
        {
            switch (evnt)
            {
                case ProductShipped shipProduct:
                    Apply(shipProduct);
                    break;
                case ProductReceived receiveProduct:
                    Apply(receiveProduct);
                    break;
                case InventoryAdjusted inventoryAdjusted:
                    Apply(inventoryAdjusted);
                    break;
                default:
                    throw new InvalidOperationException("Unsupported Event.");
            }

            _allEvents.Add(evnt);
        }

        private void AddEvent(IEvent evnt)
        {
            ApplyEvent(evnt);
            _uncommittedEvents.Add(evnt);
        }

        public IList<IEvent> GetUncommittedEvents()
        {
            return new List<IEvent>(_uncommittedEvents);
        }

        public IList<IEvent> GetAllEvents()
        {
            return new List<IEvent>(_allEvents);
        }

        public void EventsCommitted()
        {
            _uncommittedEvents.Clear();
        }

        public int GetQuantityOnHand()
        {
            return _warehouseProductState.QuantityOnHand;
        }
    }

    public class InvalidDomainException : Exception
    {
        public InvalidDomainException(string message) : base(message)
        {

        }
    }
}