Show current catalog price and price-change nudge on inventory detail

Surfaces the synced CatalogReferencePrice on the inventory detail pricing card:
"Current Catalog Price" (the price quotes use), with an info popover clarifying
it doesn't affect Unit Cost or stock value, an "Updated <date>" line, and a
badge nudging when it differs from what they last paid ("Price up/down from
$X last paid"). Adds CatalogReferencePrice/CatalogPriceUpdatedAt to
InventoryItemDto (auto-mapped). Display only — no pricing/accounting impact.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-17 15:50:11 -04:00
parent c22537b68f
commit 0f6eef5370
2 changed files with 37 additions and 0 deletions
@@ -37,6 +37,8 @@ public class InventoryItemDto
public decimal AverageCost { get; set; } public decimal AverageCost { get; set; }
public decimal LastPurchasePrice { get; set; } public decimal LastPurchasePrice { get; set; }
public DateTime? LastPurchaseDate { get; set; } public DateTime? LastPurchaseDate { get; set; }
public decimal? CatalogReferencePrice { get; set; }
public DateTime? CatalogPriceUpdatedAt { get; set; }
public int? PrimaryVendorId { get; set; } public int? PrimaryVendorId { get; set; }
public string? PrimaryVendorName { get; set; } public string? PrimaryVendorName { get; set; }
public string? VendorPartNumber { get; set; } public string? VendorPartNumber { get; set; }
@@ -431,6 +431,41 @@
<label class="text-muted small mb-1">Total Stock Value</label> <label class="text-muted small mb-1">Total Stock Value</label>
<p class="fw-semibold text-primary mb-0 fs-5">@((Model.QuantityOnHand * Model.UnitCost).ToString("C"))</p> <p class="fw-semibold text-primary mb-0 fs-5">@((Model.QuantityOnHand * Model.UnitCost).ToString("C"))</p>
</div> </div>
@if (Model.CatalogReferencePrice.HasValue && Model.CatalogReferencePrice.Value > 0)
{
<div class="col-12"><hr class="my-2" /></div>
<div class="col-12">
<label class="text-muted small mb-1">
Current Catalog Price
<i class="bi bi-info-circle ms-1" role="button" tabindex="0"
data-bs-toggle="popover" data-bs-trigger="hover focus" data-bs-placement="top"
data-bs-content="The current list price from the linked manufacturer catalog, refreshed by sync. New quotes use this price. It does not change your Unit Cost or stock value."></i>
</label>
<p class="fw-semibold text-success mb-0 fs-5">
@Model.CatalogReferencePrice.Value.ToString("C")
<span class="text-muted fs-6 fw-normal">/ @Model.UnitOfMeasure</span>
</p>
@{
var catRef = Model.CatalogReferencePrice.Value;
var paidPrice = (Model.LastPurchaseDate.HasValue && Model.LastPurchasePrice > 0)
? Model.LastPurchasePrice : Model.UnitCost;
}
@if (paidPrice > 0 && Math.Abs(catRef - paidPrice) >= 0.01m)
{
var priceUp = catRef > paidPrice;
<div class="mt-1">
<span class="badge @(priceUp ? "bg-warning text-dark" : "bg-info text-dark")">
<i class="bi @(priceUp ? "bi-arrow-up-right" : "bi-arrow-down-right") me-1"></i>
Price @(priceUp ? "up" : "down") from @paidPrice.ToString("C") last paid
</span>
</div>
}
@if (Model.CatalogPriceUpdatedAt.HasValue)
{
<div class="text-muted small mt-1">Updated @Model.CatalogPriceUpdatedAt.Value.ToLocalTime().ToString("MMM d, yyyy")</div>
}
</div>
}
@if (Model.LastPurchaseDate.HasValue) @if (Model.LastPurchaseDate.HasValue)
{ {
<div class="col-6"> <div class="col-6">