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