using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations.Schema; namespace Lagerbestand.Models; /// /// Status of a tire stack in the storage system /// public enum TireStackStatus { /// /// Tires are currently stored in the warehouse /// Stored = 0, /// /// Tires have been picked up by the customer /// PickedUp = 1, /// /// Tires have been disposed/recycled /// Disposed = 2, /// /// Tires are reserved for pickup /// Reserved = 3, /// /// Tires are in inventory (shop stock, not customer-owned) /// Inventory = 4, /// /// Tires are currently mounted on the customer's vehicle (after a seasonal swap). /// They can be re-stored later when swapping back. /// OnVehicle = 5 } /// /// Represents a stack of exactly 4 tires as a single indivisible unit. /// A stack is always 4 identical tires - there is no variable count. /// This is the main entity that tracks customer tire storage and shop inventory. /// public class TireStack { /// /// Number of tires in a stack - always 4 /// public const int TiresPerStack = 4; [Key] public Guid Id { get; set; } = Guid.NewGuid(); /// /// Custom item count for inventory (default: 4 = standard stack). /// Only used for inventory items. Customer stacks always use TiresPerStack. /// [Range(1, 99)] public int ItemCount { get; set; } = TiresPerStack; /// /// Unique identifier/ticket number for this tire stack (e.g., "TS-2024-0001") /// This serves as the primary human-readable identifier. /// [Required] [MaxLength(50)] public string TicketNumber { get; set; } = string.Empty; /// /// Customer who owns these tires (null for shop inventory) /// public Guid? CustomerId { get; set; } [ForeignKey(nameof(CustomerId))] public Customer? Customer { get; set; } /// /// Vehicle these tires belong to (null for shop inventory or legacy data) /// public Guid? VehicleId { get; set; } [ForeignKey(nameof(VehicleId))] public Vehicle? Vehicle { get; set; } /// /// Current storage location (null if picked up) /// public Guid? StorageLocationId { get; set; } [ForeignKey(nameof(StorageLocationId))] public StorageLocation? StorageLocation { get; set; } /// /// Tire category/type (used for inventory categorization) /// public Guid? CatalogItemId { get; set; } [ForeignKey(nameof(CatalogItemId))] public CatalogItem? CatalogItem { get; set; } /// /// Tread depth / condition measurements (e.g. imported from QR report) /// public ICollection Inspections { get; set; } = new List(); /// /// Current status of the tire stack /// public TireStackStatus Status { get; set; } = TireStackStatus.Stored; /// /// Tire size (e.g., "225/45R17") /// [MaxLength(50)] public string? TireSize { get; set; } /// /// Tire brand (e.g., "Michelin", "Continental") /// [MaxLength(100)] public string? TireBrand { get; set; } /// /// Tire model (e.g., "Pilot Sport 4", "WinterContact TS 860") /// [MaxLength(100)] public string? TireModel { get; set; } /// /// Season type /// public TireSeason Season { get; set; } = TireSeason.Sommer; /// /// Tread depth in mm (average of all 4 tires) /// [Range(0, 10)] public decimal? TreadDepth { get; set; } /// /// DOT/manufacturing date code (e.g., "2523" = week 25 of 2023) /// [MaxLength(20)] public string? DotCode { get; set; } /// /// Whether tires are mounted on rims /// public bool WithRims { get; set; } = true; /// /// Rim size if with rims (e.g., "17 Zoll") /// [MaxLength(20)] public string? RimSize { get; set; } /// /// TPMS sensors present /// public bool HasTpms { get; set; } /// /// Tire condition rating /// public TireCondition Condition { get; set; } = TireCondition.Good; /// /// Additional notes about the tire condition or special requirements /// [MaxLength(1000)] public string? Notes { get; set; } /// /// Date when tires were stored /// public DateTime StoredAt { get; set; } = DateTime.UtcNow; /// /// Date when tires were picked up /// public DateTime? PickedUpAt { get; set; } /// /// Expected pickup date (next season change) /// public DateTime? ExpectedPickupDate { get; set; } /// /// User who stored the tires /// public Guid? StoredByUserId { get; set; } /// /// User who processed the pickup /// public Guid? PickedUpByUserId { get; set; } public bool IsActive { get; set; } = true; public DateTime CreatedAt { get; set; } = DateTime.UtcNow; public DateTime? UpdatedAt { get; set; } /// /// Whether this is shop inventory (not customer-owned) /// [NotMapped] public bool IsInventory => CustomerId == null; /// /// Display name - customer name or category name for inventory /// [NotMapped] public string DisplayName => Customer?.FullName ?? CatalogItem?.Name ?? "Lagerbestand"; /// /// Summary description for display /// [NotMapped] public string Summary { get { var parts = new List(); if (!string.IsNullOrEmpty(TireBrand)) parts.Add(TireBrand); if (!string.IsNullOrEmpty(TireSize)) parts.Add(TireSize); parts.Add(Season.ToString()); if (WithRims) parts.Add("mit Felgen"); return string.Join(" | ", parts); } } /// /// Status display text in German /// [NotMapped] public string StatusText => Status switch { TireStackStatus.Stored => "Eingelagert", TireStackStatus.PickedUp => "Abgeholt", TireStackStatus.Disposed => "Entsorgt", TireStackStatus.Reserved => "Reserviert", TireStackStatus.Inventory => "Lagerbestand", TireStackStatus.OnVehicle => "Montiert", _ => "Unbekannt" }; /// /// Days stored (for billing purposes) /// [NotMapped] public int DaysStored => (PickedUpAt ?? DateTime.UtcNow).Subtract(StoredAt).Days; /// /// Condition display text in German /// [NotMapped] public string ConditionText => Condition switch { TireCondition.Excellent => "Sehr gut", TireCondition.Good => "Gut", TireCondition.Fair => "Ausreichend", TireCondition.Poor => "Mangelhaft", TireCondition.Critical => "Kritisch", _ => "Unbekannt" }; }