Auto-receive catalog powders and fix soft-deleted SKU collision
Two fixes to the "Got It" powder receive flow: 1. Skip the modal when the powder is in the master catalog. Clicking "Got It" now first calls ReceivePowderFromCatalog, which — if the powder resolves in the catalog — creates a fully populated inventory record (specs, cure, SDS/ TDS, image, pricing) and marks the coat received, no modal. Only when the powder isn't in the catalog does it fall back to the manual entry modal. The catalog match/apply and the receive finalize (opening txn, mark received, sibling-coat linking) are extracted into shared helpers used by both the modal save and the auto-receive path. 2. Fix a crash re-receiving a previously-deleted powder. The unique index IX_InventoryItems_CompanyId_SKU had no filter, so a soft-deleted item still reserved its SKU; re-creating it generated the same SKU and violated the constraint. The index is now filtered on IsDeleted = 0, matching the app's soft-delete semantics. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -1041,6 +1041,37 @@
|
||||
|
||||
// Custom powder (no inventory item) â†' open modal to add to inventory
|
||||
if (!hasInv) {
|
||||
// If the powder is already in the master catalog, receive it straight to inventory
|
||||
// with all its specs/docs — no modal. Only fall back to the modal when it isn't.
|
||||
const tokenAuto = document.querySelector('input[name="__RequestVerificationToken"]')?.value
|
||||
?? document.querySelector('meta[name="__RequestVerificationToken"]')?.content;
|
||||
this.disabled = true; qtyInput.disabled = true;
|
||||
this.innerHTML = '<span class="spinner-border spinner-border-sm"></span>';
|
||||
try {
|
||||
const autoResp = await fetch('@Url.Action("ReceivePowderFromCatalog", "Dashboard")', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded', 'RequestVerificationToken': tokenAuto },
|
||||
body: `coatId=${coatId}&lbsReceived=${lbs}`
|
||||
});
|
||||
const autoData = await autoResp.json();
|
||||
if (autoData.success) {
|
||||
fadePlacedRow(row);
|
||||
showInventoryToast('Added "' + (autoData.itemName || 'powder') + '" to inventory from the catalog.');
|
||||
return;
|
||||
}
|
||||
if (!autoData.needsDetails) {
|
||||
alert(autoData.message || 'Could not record receipt. Please try again.');
|
||||
this.disabled = false; qtyInput.disabled = false;
|
||||
this.innerHTML = '<i class="bi bi-box-arrow-in-down"></i> Got It';
|
||||
return;
|
||||
}
|
||||
// Not in catalog — fall through to the manual entry modal.
|
||||
} catch {
|
||||
// Network error — fall back to the manual entry modal.
|
||||
}
|
||||
this.disabled = false; qtyInput.disabled = false;
|
||||
this.innerHTML = '<i class="bi bi-box-arrow-in-down"></i> Got It';
|
||||
|
||||
const modal = document.getElementById('addPowderModal');
|
||||
// Pre-fill hidden + text fields
|
||||
modal.querySelector('#apm-coatId').value = coatId;
|
||||
|
||||
Reference in New Issue
Block a user