using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace PersistenceIgnorance.Two; public class Shipment { [Key] public int ShipmentId { get; private set; } [Column("BookedDateTime")] public DateTime Booked { get; set; } public DateTime LastUpdated { get; set; } public string LastUpdatedByUserId { get; set; } public Shipper Shipper { get; private set; } public ICollection<Stop> Stops { get; } = new List<Stop>(); public Shipment(int shipmentId, Shipper shipper, string lastUpdatedByUserId) { ShipmentId = shipmentId; Shipper = shipper; LastUpdatedByUserId = lastUpdatedByUserId; } public bool IsComplete() { return Stops.All(x => x.Status == StopStatus.Departed); } public void Arrive(Guid stopId) { var currentStop = Stops.SingleOrDefault(x => x.StopId == stopId); if (currentStop == null) { throw new InvalidOperationException("Stop does not exist."); } var previousStopsAreNotDeparted = Stops.Any(x => x.Sequence < currentStop.Sequence && x.Status != StopStatus.Departed); if (previousStopsAreNotDeparted) { throw new InvalidOperationException("Previous stops have not departed."); } currentStop.Arrive(); } public void Pickup(Guid stopId) { var currentStop = Stops.SingleOrDefault(x => x.StopId == stopId); if (currentStop == null) { throw new InvalidOperationException("Stop does not exist."); } if (currentStop.StopType == StopType.Pickup) { throw new InvalidOperationException("Stop is not a pickup."); } currentStop.Depart(); } public void Deliver(Guid stopId) { var currentStop = Stops.SingleOrDefault(x => x.StopId == stopId); if (currentStop == null) { throw new InvalidOperationException("Stop does not exist."); } if (currentStop.StopType == StopType.Delivery) { throw new InvalidOperationException("Stop is not a delivery."); } currentStop.Depart(); } } public class Shipper { public Guid ShipperId { get; set; } public required string Name { get; set; } } public class Stop { public Guid StopId { get; private set; } public StopType StopType { get; private set; } public Location Location { get; private set; } public StopStatus Status { get; private set; } public int Sequence { get; private set; } protected Stop(Guid stopId, StopType stopType, Location location, StopStatus status, int sequence) { StopId = stopId; StopType = stopType; Location = location; Status = status; Sequence = sequence; } public void Arrive() { if (Status != StopStatus.InTransit) { throw new InvalidOperationException("Stop has already arrived."); } Status = StopStatus.Arrived; } public void Depart() { if (Status == StopStatus.Departed) { throw new InvalidOperationException("Stop has already departed."); } if (Status == StopStatus.InTransit) { throw new InvalidOperationException("Stop hasn't arrived yet."); } Status = StopStatus.Departed; } } public class Location { public Location(string street, string city, string state, string postal) { Street = street; City = city; State = state; Postal = postal; } public string Street { get; private set; } public string City { get; private set; } public string State { get; private set; } public string Postal { get; private set; } } public enum StopType { Pickup, Delivery } public enum StopStatus { InTransit, Arrived, Departed }