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
|
return Json(new
|
||||||
{
|
{
|
||||||
success = true,
|
success = true,
|
||||||
@@ -856,6 +886,8 @@ public class InventoryController : Controller
|
|||||||
vendorName = manufacturer,
|
vendorName = manufacturer,
|
||||||
wasInCatalog = wasInCatalog,
|
wasInCatalog = wasInCatalog,
|
||||||
addedToCatalog = addedToCatalog,
|
addedToCatalog = addedToCatalog,
|
||||||
|
existingInventoryId = existingInventoryId,
|
||||||
|
existingInventoryName = existingInventoryName,
|
||||||
reasoning = aiResult.Reasoning,
|
reasoning = aiResult.Reasoning,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -404,7 +404,16 @@
|
|||||||
? ' <span class="badge bg-success ms-1">Added to platform catalog</span>'
|
? ' <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}`);
|
showFormStatus('success', `Filled from label scan: ${filled.join(', ')}.${catalogNote}`);
|
||||||
} else {
|
} else {
|
||||||
showFormStatus('warning', `Label scanned but no empty fields to fill.${catalogNote}`);
|
showFormStatus('warning', `Label scanned but no empty fields to fill.${catalogNote}`);
|
||||||
|
|||||||
Reference in New Issue
Block a user