Files
PowderCoatingLogix/src/PowderCoating.Application/DTOs/AI/CatalogPriceCheckDtos.cs
T
spouliot 54f444d981 Add AI Catalog Price Check feature
Claude reviews every active catalog item against the shop's own operating costs
and returns a per-item verdict (below-cost / thin-margin / high / ok) with a
suggested price range, cost floor, and assumptions.

- New entity: CatalogPriceCheckReport (JSON blob, archived per company)
- New service: IAiCatalogPriceCheckService / AiCatalogPriceCheckService
  batches items 25 at a time to stay within model context limits
- Two new controller actions: GET AiPriceCheck (view report) + POST RunAiPriceCheck
- AiPriceCheck view: summary cards (counts by verdict), color-coded item cards
  with Edit Price link, assumptions detail, and loading spinner on submit
- AI Price Check button added to catalog Index header
- Migration AddCatalogPriceCheckReport applied

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-25 18:41:56 -04:00

81 lines
3.4 KiB
C#

namespace PowderCoating.Application.DTOs.AI;
// ── Input ─────────────────────────────────────────────────────────────────────
/// <summary>Lightweight representation of a catalog item sent to Claude for analysis.</summary>
public class CatalogItemForPriceCheck
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string? Description { get; set; }
public string CategoryName { get; set; } = string.Empty;
public decimal CurrentPrice { get; set; }
public decimal? ApproximateAreaSqFt { get; set; }
public int? EstimatedMinutes { get; set; }
public bool RequiresSandblasting { get; set; }
public bool RequiresMasking { get; set; }
}
/// <summary>Operating cost summary injected into the Claude system prompt.</summary>
public class ShopOperatingCostSummary
{
public decimal LaborRatePerHour { get; set; }
public decimal OvenCostPerHour { get; set; }
public decimal SandblasterCostPerHour { get; set; }
public decimal CoatingBoothCostPerHour { get; set; }
public decimal PowderCostPerSqFt { get; set; }
public decimal ShopSuppliesRatePercent { get; set; }
public decimal MarkupOrMarginPercent { get; set; }
public string PricingMode { get; set; } = "markup"; // "markup" or "margin"
public decimal ShopMinimumCharge { get; set; }
public string? AiContextProfile { get; set; }
}
// ── Per-Item Result ───────────────────────────────────────────────────────────
/// <summary>Verdict on a single catalog item's price health.</summary>
public class CatalogItemPriceVerdict
{
public int CatalogItemId { get; set; }
public string Name { get; set; } = string.Empty;
public decimal CurrentPrice { get; set; }
/// <summary>Assumptions Claude made about size/complexity to estimate costs.</summary>
public string Assumptions { get; set; } = string.Empty;
public decimal EstimatedSqFtMin { get; set; }
public decimal EstimatedSqFtMax { get; set; }
public int EstimatedMinutesMin { get; set; }
public int EstimatedMinutesMax { get; set; }
/// <summary>Calculated cost floor using the shop's own rates.</summary>
public decimal CostFloor { get; set; }
/// <summary>ok | low | high | below-cost</summary>
public string Verdict { get; set; } = "ok";
public decimal SuggestedPriceMin { get; set; }
public decimal SuggestedPriceMax { get; set; }
/// <summary>high | medium | low</summary>
public string Confidence { get; set; } = "medium";
public string Reasoning { get; set; } = string.Empty;
}
// ── Report ────────────────────────────────────────────────────────────────────
public class CatalogPriceCheckReportDto
{
public int Id { get; set; }
public DateTime RunAt { get; set; }
public int ItemsChecked { get; set; }
public int BelowCostCount { get; set; }
public int LowMarginCount { get; set; }
public int HighPriceCount { get; set; }
public int OkCount { get; set; }
public List<CatalogItemPriceVerdict> Results { get; set; } = new();
public string OperatingCostsSummary { get; set; } = string.Empty;
}