Initial commit

This commit is contained in:
2026-04-23 21:38:24 -04:00
commit 63e12a9636
1762 changed files with 1672620 additions and 0 deletions
@@ -0,0 +1,128 @@
namespace PowderCoating.Application.DTOs.Powder;
/// <summary>Readiness state — controls which layers are shown in the UI.</summary>
public class PowderDataReadiness
{
public int JobsWithActualData { get; set; }
public int Layer3MinJobs { get; set; }
public int Layer2MinJobs { get; set; }
public bool IsLayer2Ready { get; set; }
public bool IsLayer3Ready { get; set; }
public int Layer3ProgressPercent { get; set; } // 0-100, for the progress bar
}
/// <summary>Per-job powder summary: estimated vs actual vs variance.</summary>
public class JobPowderSummaryDto
{
public int JobId { get; set; }
public string JobNumber { get; set; } = string.Empty;
public List<CoatPowderSummaryDto> Coats { get; set; } = new();
public decimal TotalEstimatedLbs { get; set; }
public decimal TotalActualLbs { get; set; }
public decimal TotalVarianceLbs { get; set; }
public bool HasAllActuals { get; set; }
}
public class CoatPowderSummaryDto
{
public int JobItemCoatId { get; set; }
public int JobItemId { get; set; }
public string ItemDescription { get; set; } = string.Empty;
public string CoatName { get; set; } = string.Empty;
public string? ColorName { get; set; }
public string? InventoryItemName { get; set; }
public decimal? EstimatedLbs { get; set; }
public decimal? ActualLbs { get; set; }
public decimal? VarianceLbs { get; set; }
public decimal? VariancePct { get; set; }
public bool IsRecorded { get; set; }
}
/// <summary>Layer 2: Low stock alert with job pipeline demand forecast.</summary>
public class LowStockForecastDto
{
public int InventoryItemId { get; set; }
public string Name { get; set; } = string.Empty;
public string? ColorName { get; set; }
public string? ColorCode { get; set; }
public string? Manufacturer { get; set; }
public decimal CurrentStockLbs { get; set; }
public decimal ScheduledDemandLbs { get; set; } // Sum of PowderToOrder on active jobs
public decimal ReorderPoint { get; set; }
public decimal ReorderQuantity { get; set; }
public decimal ShortfallLbs { get; set; } // Max(0, Demand - Stock)
public bool IsAtRisk { get; set; } // Stock < Demand
public bool IsBelowReorderPoint { get; set; } // Stock < ReorderPoint
public int ActiveJobCount { get; set; } // # of active jobs needing this powder
}
/// <summary>Layer 2: Per-SKU coverage efficiency — actual vs catalog spec.</summary>
public class PowderEfficiencyDto
{
public int InventoryItemId { get; set; }
public string Name { get; set; } = string.Empty;
public string? ColorName { get; set; }
public string? Manufacturer { get; set; }
public decimal CatalogCoverageSqFtPerLb { get; set; } // What the spec says
public decimal ActualAvgCoverageSqFtPerLb { get; set; } // What we're actually getting
public decimal VariancePct { get; set; } // (Actual - Catalog) / Catalog * 100
public int SampleCount { get; set; } // # of coats with actuals
public decimal TotalEstimatedLbs { get; set; }
public decimal TotalActualLbs { get; set; }
public bool IsBelowSpec { get; set; } // Actual < Catalog (wasting powder)
public bool HasEnoughData { get; set; } // SampleCount >= 5
}
/// <summary>Layer 3: Suggested reorder quantity based on pipeline + historical usage.</summary>
public class PowderReorderSuggestionDto
{
public int InventoryItemId { get; set; }
public string Name { get; set; } = string.Empty;
public string? ColorName { get; set; }
public string? Manufacturer { get; set; }
public decimal CurrentStockLbs { get; set; }
public decimal PipelineDemand30DaysLbs { get; set; } // Scheduled jobs next 30 days
public decimal HistoricalAvgMonthlyUsageLbs { get; set; } // Based on actual data
public decimal SuggestedOrderQtyLbs { get; set; } // Calculated suggestion
public decimal ConfiguredReorderQty { get; set; } // InventoryItem.ReorderQuantity
public int SampleJobCount { get; set; } // # of completed jobs used in calculation
public decimal ConfidenceScore { get; set; } // 0-1, based on sample size
}
/// <summary>Layer 3: Jobs where actual powder significantly exceeded estimate.</summary>
public class WastePatternDto
{
public int JobId { get; set; }
public string JobNumber { get; set; } = string.Empty;
public string ItemDescription { get; set; } = string.Empty;
public string CoatName { get; set; } = string.Empty;
public string? InventoryItemName { get; set; }
public string? Complexity { get; set; }
public decimal EstimatedLbs { get; set; }
public decimal ActualLbs { get; set; }
public decimal OveragePct { get; set; }
public DateTime JobDate { get; set; }
}
/// <summary>Dashboard view model combining all layers.</summary>
public class PowderInsightsDashboardDto
{
public PowderDataReadiness Readiness { get; set; } = new();
public List<LowStockForecastDto> LowStockAlerts { get; set; } = new(); // Layer 2
public List<PowderEfficiencyDto> EfficiencyBySku { get; set; } = new(); // Layer 2
public List<PowderReorderSuggestionDto> ReorderSuggestions { get; set; } = new(); // Layer 3
public List<WastePatternDto> WastePatterns { get; set; } = new(); // Layer 3
public int ActiveJobsNeedingPowder { get; set; }
public decimal TotalEstimatedPowderNeededLbs { get; set; }
}
/// <summary>Result returned from RecordUsage AJAX call.</summary>
public class RecordUsageResultDto
{
public bool Success { get; set; }
public string? ErrorMessage { get; set; }
public decimal ActualLbs { get; set; }
public decimal EstimatedLbs { get; set; }
public decimal VarianceLbs { get; set; }
public decimal VariancePct { get; set; }
}