Add vendor supply categories with inventory auto-filter
Vendors can now be tagged with one or more inventory categories (Powder, Chemical, etc.) via checkboxes on the Create/Edit form. The inventory Create/Edit vendor dropdown automatically filters to matching vendors when a category is selected; falls back to all vendors if none are tagged. Includes migration AddVendorCategories (VendorInventoryCategories join table). Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -345,6 +345,10 @@
|
||||
<option value="">Select vendor</option>
|
||||
<option value="__new__">+ Add New Vendor…</option>
|
||||
</select>
|
||||
<div id="vendor-filter-note" class="form-text d-none">
|
||||
<i class="bi bi-funnel me-1 text-info"></i><span class="text-info">Showing vendors for this category.</span>
|
||||
<a href="#" id="vendor-filter-clear" class="ms-1">Show all</a>
|
||||
</div>
|
||||
<span asp-validation-for="PrimaryVendorId" class="text-danger"></span>
|
||||
</div>
|
||||
</div>
|
||||
@@ -438,4 +442,38 @@
|
||||
{
|
||||
<script src="~/js/inventory-label-scan.js"></script>
|
||||
}
|
||||
<script>
|
||||
(function () {
|
||||
const categoryVendorMap = @Html.Raw(ViewBag.CategoryVendorMapJson ?? "{}");
|
||||
const vendorSelect = document.getElementById('field-vendor');
|
||||
const allVendorOptions = Array.from(vendorSelect.options).map(o => ({ v: o.value, t: o.text }));
|
||||
|
||||
function filterVendors(catId, forceAll) {
|
||||
const vendorIds = (!forceAll && catId) ? (categoryVendorMap[catId] || []) : [];
|
||||
const isFiltered = vendorIds.length > 0;
|
||||
const currentVal = vendorSelect.value;
|
||||
|
||||
vendorSelect.innerHTML = '';
|
||||
allVendorOptions.forEach(function (opt) {
|
||||
if (!isFiltered || !opt.v || opt.v === '__new__' || vendorIds.includes(Number(opt.v)))
|
||||
vendorSelect.add(new Option(opt.t, opt.v));
|
||||
});
|
||||
|
||||
if (Array.from(vendorSelect.options).some(o => o.value === currentVal))
|
||||
vendorSelect.value = currentVal;
|
||||
|
||||
document.getElementById('vendor-filter-note').classList.toggle('d-none', !isFiltered);
|
||||
}
|
||||
|
||||
document.getElementById('field-category').addEventListener('change', function () {
|
||||
filterVendors(this.value, false);
|
||||
});
|
||||
document.getElementById('vendor-filter-clear')?.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
filterVendors(document.getElementById('field-category').value, true);
|
||||
});
|
||||
|
||||
filterVendors(document.getElementById('field-category').value, false);
|
||||
})();
|
||||
</script>
|
||||
}
|
||||
|
||||
@@ -341,6 +341,10 @@
|
||||
<option value="">Select vendor</option>
|
||||
<option value="__new__">+ Add New Vendor…</option>
|
||||
</select>
|
||||
<div id="vendor-filter-note" class="form-text d-none">
|
||||
<i class="bi bi-funnel me-1 text-info"></i><span class="text-info">Showing vendors for this category.</span>
|
||||
<a href="#" id="vendor-filter-clear" class="ms-1">Show all</a>
|
||||
</div>
|
||||
<span asp-validation-for="PrimaryVendorId" class="text-danger"></span>
|
||||
</div>
|
||||
<div class="col-12">
|
||||
@@ -457,4 +461,39 @@
|
||||
{
|
||||
<script src="~/js/inventory-label-scan.js"></script>
|
||||
}
|
||||
<script>
|
||||
(function () {
|
||||
const categoryVendorMap = @Html.Raw(ViewBag.CategoryVendorMapJson ?? "{}");
|
||||
const vendorSelect = document.getElementById('field-vendor');
|
||||
const allVendorOptions = Array.from(vendorSelect.options).map(o => ({ v: o.value, t: o.text }));
|
||||
|
||||
function filterVendors(catId, forceAll) {
|
||||
const vendorIds = (!forceAll && catId) ? (categoryVendorMap[catId] || []) : [];
|
||||
const isFiltered = vendorIds.length > 0;
|
||||
const currentVal = vendorSelect.value;
|
||||
|
||||
vendorSelect.innerHTML = '';
|
||||
allVendorOptions.forEach(function (opt) {
|
||||
if (!isFiltered || !opt.v || opt.v === '__new__' || vendorIds.includes(Number(opt.v)))
|
||||
vendorSelect.add(new Option(opt.t, opt.v));
|
||||
});
|
||||
|
||||
if (Array.from(vendorSelect.options).some(o => o.value === currentVal))
|
||||
vendorSelect.value = currentVal;
|
||||
|
||||
document.getElementById('vendor-filter-note').classList.toggle('d-none', !isFiltered);
|
||||
}
|
||||
|
||||
document.getElementById('field-category').addEventListener('change', function () {
|
||||
filterVendors(this.value, false);
|
||||
});
|
||||
document.getElementById('vendor-filter-clear')?.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
filterVendors(document.getElementById('field-category').value, true);
|
||||
});
|
||||
|
||||
// Apply on load — Edit already has a category selected
|
||||
filterVendors(document.getElementById('field-category').value, false);
|
||||
})();
|
||||
</script>
|
||||
}
|
||||
|
||||
@@ -195,6 +195,27 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Supply Categories -->
|
||||
@if (ViewBag.VendorCategories is IEnumerable<PowderCoating.Core.Entities.InventoryCategoryLookup> cats && cats.Any())
|
||||
{
|
||||
<div class="mb-4">
|
||||
<h5 class="border-bottom pb-2 mb-3">
|
||||
<i class="bi bi-tags me-2 text-primary"></i>Supply Categories
|
||||
</h5>
|
||||
<div class="d-flex flex-wrap gap-3">
|
||||
@foreach (var cat in cats)
|
||||
{
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox"
|
||||
name="CategoryIds" value="@cat.Id" id="cat_@cat.Id" />
|
||||
<label class="form-check-label" for="cat_@cat.Id">@cat.DisplayName</label>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="form-text">Tag this vendor with the types of supplies they provide. Used to filter the vendor list when adding inventory items.</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Notes Section -->
|
||||
<div class="mb-4">
|
||||
<h5 class="border-bottom pb-2 mb-3">
|
||||
|
||||
@@ -198,6 +198,29 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Supply Categories -->
|
||||
@if (ViewBag.VendorCategories is IEnumerable<PowderCoating.Core.Entities.InventoryCategoryLookup> cats && cats.Any())
|
||||
{
|
||||
var selectedCatIds = (HashSet<int>)ViewBag.SelectedCategoryIds;
|
||||
<div class="mb-4">
|
||||
<h5 class="border-bottom pb-2 mb-3">
|
||||
<i class="bi bi-tags me-2 text-primary"></i>Supply Categories
|
||||
</h5>
|
||||
<div class="d-flex flex-wrap gap-3">
|
||||
@foreach (var cat in cats)
|
||||
{
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox"
|
||||
name="CategoryIds" value="@cat.Id" id="cat_@cat.Id"
|
||||
@(selectedCatIds.Contains(cat.Id) ? "checked" : "") />
|
||||
<label class="form-check-label" for="cat_@cat.Id">@cat.DisplayName</label>
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
<div class="form-text">Tag this vendor with the types of supplies they provide. Used to filter the vendor list when adding inventory items.</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
<!-- Notes Section -->
|
||||
<div class="mb-4">
|
||||
<h5 class="border-bottom pb-2 mb-3">
|
||||
|
||||
Reference in New Issue
Block a user