Add AI Quick Quote widget and inline customer reassignment
- New AI Quick Quote floating button: staff type a verbal description to get an instant price estimate for phone/walk-in customers; detected color names are fuzzy-matched against inventory for stock status; saves draft quote under a Walk-In / Phone customer with one click - Inline customer change on Quote Details and Job Details: always-visible native select with inline confirmation banner (no TomSelect dependency); ChangeCustomer AJAX endpoints on QuotesController and JobsController - Quote Edit page: customer dropdown is now editable (lock removed) - Fix AutoMapper missing CatalogCategory -> UpdateCategoryDto mapping that caused a crash on the catalog category Edit page - Help docs and AI knowledge base updated for all three features Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
namespace PowderCoating.Application.DTOs.AI;
|
||||
|
||||
/// <summary>Request from the Quick Quote widget to analyze a verbal/phone description.</summary>
|
||||
public class AiQuickQuoteRequest
|
||||
{
|
||||
public string Description { get; set; } = string.Empty;
|
||||
public int Quantity { get; set; } = 1;
|
||||
public int CoatCount { get; set; } = 1;
|
||||
public int CompanyId { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>Result returned to the Quick Quote widget after AI analysis.</summary>
|
||||
public class AiQuickQuoteResult
|
||||
{
|
||||
public bool Success { get; set; }
|
||||
public string? ErrorMessage { get; set; }
|
||||
|
||||
public string Description { get; set; } = string.Empty;
|
||||
public decimal SurfaceAreaSqFt { get; set; }
|
||||
public string Complexity { get; set; } = "Moderate";
|
||||
public int EstimatedMinutes { get; set; }
|
||||
public bool RequiresPreheat { get; set; }
|
||||
public int PreheatMinutes { get; set; }
|
||||
public string Confidence { get; set; } = "Medium";
|
||||
public string? Reasoning { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Detected color names from the description with server-resolved inventory stock status.
|
||||
/// Populated by the controller after the AI call — the service populates DetectedColorName only.
|
||||
/// </summary>
|
||||
public List<PowderStockMatch> PowderMatches { get; set; } = new();
|
||||
|
||||
public decimal EstimatedUnitPrice { get; set; }
|
||||
public decimal EstimatedTotal { get; set; }
|
||||
public AiPricingBreakdown? Breakdown { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>Inventory stock result for a powder color the customer mentioned.</summary>
|
||||
public class PowderStockMatch
|
||||
{
|
||||
/// <summary>Color name exactly as extracted by Claude from the customer description.</summary>
|
||||
public string DetectedColorName { get; set; } = string.Empty;
|
||||
/// <summary>Matched inventory item display name; null when no inventory match was found.</summary>
|
||||
public string? InventoryItemName { get; set; }
|
||||
public decimal QuantityOnHand { get; set; }
|
||||
public decimal UnitCost { get; set; }
|
||||
public bool IsInStock { get; set; }
|
||||
public bool HasInventoryMatch { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>Request to persist the quick quote estimate as a draft Quote record.</summary>
|
||||
public class SaveQuickQuoteRequest
|
||||
{
|
||||
/// <summary>Caller identifier — used as the quote CustomerPO (e.g., "John - 4 wheels").</summary>
|
||||
public string Reference { get; set; } = string.Empty;
|
||||
public string OriginalDescription { get; set; } = string.Empty;
|
||||
public string AiDescription { get; set; } = string.Empty;
|
||||
public decimal SurfaceAreaSqFt { get; set; }
|
||||
public string Complexity { get; set; } = "Moderate";
|
||||
public int EstimatedMinutes { get; set; }
|
||||
public bool RequiresPreheat { get; set; }
|
||||
public int PreheatMinutes { get; set; }
|
||||
public int Quantity { get; set; } = 1;
|
||||
public int CoatCount { get; set; } = 1;
|
||||
public decimal EstimatedUnitPrice { get; set; }
|
||||
public decimal MaterialCost { get; set; }
|
||||
public decimal LaborCost { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>Internal JSON schema returned by Claude for quick quote analysis.</summary>
|
||||
public class ClaudeQuickQuoteResponse
|
||||
{
|
||||
public string Description { get; set; } = string.Empty;
|
||||
public decimal SurfaceAreaSqFt { get; set; }
|
||||
public string Complexity { get; set; } = "Moderate";
|
||||
public int EstimatedMinutes { get; set; }
|
||||
public bool RequiresPreheat { get; set; }
|
||||
public int PreheatMinutes { get; set; }
|
||||
public string Confidence { get; set; } = "Medium";
|
||||
public string Reasoning { get; set; } = string.Empty;
|
||||
/// <summary>Color/powder names verbatim from the customer description — server resolves inventory stock.</summary>
|
||||
public List<string> DetectedColorNames { get; set; } = new();
|
||||
}
|
||||
Reference in New Issue
Block a user