Warn on label scan when product already exists in tenant inventory
After resolving manufacturer + SKU from the scan, ScanLabel now queries the tenant's InventoryItems: first by ManufacturerPartNumber exact match (most precise), then by ColorName + Manufacturer fuzzy match as fallback. If a match is found, the response includes existingInventoryId and existingInventoryName. The JS fillFromScan() shows a warning banner with a direct link to the existing item instead of the normal success message. Form fields are still pre-filled so the user can proceed to add a new entry (e.g. a different lot or bag size) if that was the intent. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -834,6 +834,36 @@ public class InventoryController : Controller
|
||||
}
|
||||
}
|
||||
|
||||
// Check if this product already exists in the tenant's inventory.
|
||||
// Match by ManufacturerPartNumber first (most precise); fall back to color name + manufacturer.
|
||||
// Returns the first active match so the UI can warn the user before they create a duplicate.
|
||||
int? existingInventoryId = null;
|
||||
string? existingInventoryName = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(sku))
|
||||
{
|
||||
var skuLower = sku.ToLower();
|
||||
var byPart = await _unitOfWork.InventoryItems.FindAsync(i =>
|
||||
i.ManufacturerPartNumber != null &&
|
||||
i.ManufacturerPartNumber.ToLower() == skuLower);
|
||||
var hit = byPart.FirstOrDefault();
|
||||
if (hit != null) { existingInventoryId = hit.Id; existingInventoryName = hit.Name; }
|
||||
}
|
||||
|
||||
if (existingInventoryId == null && !string.IsNullOrEmpty(colorName))
|
||||
{
|
||||
var nameLower = colorName.ToLower();
|
||||
var mfrLower = manufacturer?.ToLower() ?? "";
|
||||
var byName = await _unitOfWork.InventoryItems.FindAsync(i =>
|
||||
(i.ColorName != null && i.ColorName.ToLower() == nameLower) ||
|
||||
i.Name.ToLower() == nameLower);
|
||||
var hit = byName.FirstOrDefault(i =>
|
||||
string.IsNullOrEmpty(mfrLower) ||
|
||||
(i.Manufacturer ?? "").ToLower().Contains(mfrLower) ||
|
||||
mfrLower.Contains((i.Manufacturer ?? "").ToLower().Trim()));
|
||||
if (hit != null) { existingInventoryId = hit.Id; existingInventoryName = hit.Name; }
|
||||
}
|
||||
|
||||
return Json(new
|
||||
{
|
||||
success = true,
|
||||
@@ -856,6 +886,8 @@ public class InventoryController : Controller
|
||||
vendorName = manufacturer,
|
||||
wasInCatalog = wasInCatalog,
|
||||
addedToCatalog = addedToCatalog,
|
||||
existingInventoryId = existingInventoryId,
|
||||
existingInventoryName = existingInventoryName,
|
||||
reasoning = aiResult.Reasoning,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -404,7 +404,16 @@
|
||||
? ' <span class="badge bg-success ms-1">Added to platform catalog</span>'
|
||||
: '';
|
||||
|
||||
if (filled.length > 0) {
|
||||
if (data.existingInventoryId) {
|
||||
const itemName = data.existingInventoryName || data.colorName || 'This product';
|
||||
const filledNote = filled.length > 0 ? ` Fields pre-filled from scan.` : '';
|
||||
showFormStatus('warning',
|
||||
`<i class="bi bi-exclamation-triangle-fill me-1"></i>` +
|
||||
`<strong>${itemName}</strong> is already in your inventory. ` +
|
||||
`<a href="/Inventory/Details/${data.existingInventoryId}" class="alert-link fw-semibold">View existing item</a>` +
|
||||
` — or continue below to add a new entry (e.g. a new lot or bag size).${filledNote}${catalogNote}`
|
||||
);
|
||||
} else if (filled.length > 0) {
|
||||
showFormStatus('success', `Filled from label scan: ${filled.join(', ')}.${catalogNote}`);
|
||||
} else {
|
||||
showFormStatus('warning', `Label scanned but no empty fields to fill.${catalogNote}`);
|
||||
|
||||
Reference in New Issue
Block a user