Initial commit: Lagerbestand Blazor Projekt

This commit is contained in:
spaethf committed 2026-09-21 21:28:23 +02:00
commit cba9414e92
105 files changed
+36431

No files matched your search

+259
View File
@@ -0,0 +1,259 @@
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"
};
}