- | ${escapeHtml(item.lot_name)} |
+
+
+
+
+ |
${escapeHtml(item.description || comp?.description || '')} |
${formatPriceOrNA(item.estimate_price ?? item.unit_price)} |
@@ -1511,8 +1535,6 @@ function renderMultiSelectTabWithSections(sections) {
});
// Add empty row for new item in this section
- const sectionId = section.categories.join('-');
- const categoriesStr = section.categories.join(',');
html += `
|
|
@@ -1640,6 +1662,10 @@ function renderAutocomplete() {
onmousedown = `selectAutocompleteItemSection(${idx}, '${autocompleteCategory}')`;
} else if (autocompleteMode === 'multi') {
onmousedown = `selectAutocompleteItemMulti(${idx})`;
+ } else if (autocompleteMode === 'bom') {
+ onmousedown = `selectAutocompleteItemBOM(${idx}, ${autocompleteCategory})`;
+ } else if (autocompleteMode === 'edit-item') {
+ onmousedown = `selectAutocompleteEditItem(${idx})`;
} else {
// single mode
onmousedown = `selectAutocompleteItem(${idx})`;
@@ -1921,6 +1947,138 @@ function selectAutocompleteItemSection(index, sectionId) {
schedulePriceLevelsRefresh({ delay: 80, rerender: true, autosave: false });
}
+// Autocomplete for editing an existing cart item's LOT (multi/section tabs)
+async function showAutocompleteEditItem(lotName, input) {
+ autocompleteInput = input;
+ autocompleteCategory = lotName;
+ autocompleteMode = 'edit-item';
+ autocompleteIndex = -1;
+ autocompleteEditCategories = input.dataset.categories
+ ? input.dataset.categories.split(',').map(c => c.trim().toUpperCase())
+ : null;
+ const components = getComponentsForTab(currentTab);
+ await ensurePricesLoaded(components);
+ filterAutocompleteEditItem(input.value);
+}
+
+function filterAutocompleteEditItem(search) {
+ const searchLower = (search || '').toLowerCase();
+ const components = autocompleteEditCategories
+ ? allComponents.filter(c => autocompleteEditCategories.includes(getComponentCategory(c)))
+ : getComponentsForTab(currentTab);
+ autocompleteFiltered = components.filter(c => {
+ if (!hasComponentPrice(c.lot_name)) return false;
+ if (!isComponentAllowedByStockFilter(c)) return false;
+ return (c.lot_name + ' ' + (c.description || '')).toLowerCase().includes(searchLower);
+ }).sort((a, b) => {
+ const d = (b.popularity_score || 0) - (a.popularity_score || 0);
+ return d !== 0 ? d : a.lot_name.localeCompare(b.lot_name);
+ });
+ renderAutocomplete();
+}
+
+function handleAutocompleteKeyEditItem(event) {
+ if (event.key === 'ArrowDown') {
+ event.preventDefault();
+ autocompleteIndex = Math.min(autocompleteIndex + 1, autocompleteFiltered.length - 1);
+ renderAutocomplete();
+ } else if (event.key === 'ArrowUp') {
+ event.preventDefault();
+ autocompleteIndex = Math.max(autocompleteIndex - 1, -1);
+ renderAutocomplete();
+ } else if (event.key === 'Enter') {
+ event.preventDefault();
+ if (autocompleteIndex >= 0 && autocompleteIndex < autocompleteFiltered.length) {
+ selectAutocompleteEditItem(autocompleteIndex);
+ }
+ } else if (event.key === 'Escape') {
+ hideAutocomplete();
+ }
+}
+
+function selectAutocompleteEditItem(index) {
+ const comp = autocompleteFiltered[index];
+ if (!comp) return;
+ const lotName = autocompleteCategory;
+ const oldItem = cart.find(i => i.lot_name === lotName);
+ const qty = oldItem?.quantity || 1;
+ cart = cart.filter(i => i.lot_name !== lotName);
+ const price = componentPricesCache[comp.lot_name] || 0;
+ cart.push({
+ lot_name: comp.lot_name,
+ quantity: qty,
+ unit_price: price,
+ estimate_price: price,
+ warehouse_price: null,
+ competitor_price: null,
+ delta_wh_estimate_abs: null,
+ delta_wh_estimate_pct: null,
+ delta_comp_estimate_abs: null,
+ delta_comp_estimate_pct: null,
+ delta_comp_wh_abs: null,
+ delta_comp_wh_pct: null,
+ price_missing: ['warehouse', 'competitor'],
+ description: comp.description || '',
+ category: getComponentCategory(comp)
+ });
+ hideAutocomplete();
+ renderTab();
+ updateCartUI();
+ triggerAutoSave();
+ schedulePriceLevelsRefresh({ delay: 80, rerender: true, autosave: false });
+}
+
+// Autocomplete for BOM LOT mapping
+function showAutocompleteBOM(rowIdx, input) {
+ autocompleteInput = input;
+ autocompleteCategory = rowIdx;
+ autocompleteMode = 'bom';
+ autocompleteIndex = -1;
+ filterAutocompleteBOM(rowIdx, input.value);
+}
+
+function filterAutocompleteBOM(rowIdx, search) {
+ const searchLower = (search || '').toLowerCase();
+ autocompleteFiltered = (window._bomAllComponents || allComponents).filter(c => {
+ const text = (c.lot_name + ' ' + (c.description || '')).toLowerCase();
+ return text.includes(searchLower);
+ }).sort((a, b) => {
+ const popDiff = (b.popularity_score || 0) - (a.popularity_score || 0);
+ if (popDiff !== 0) return popDiff;
+ return a.lot_name.localeCompare(b.lot_name);
+ });
+ renderAutocomplete();
+}
+
+function handleAutocompleteKeyBOM(event, rowIdx) {
+ if (event.key === 'ArrowDown') {
+ event.preventDefault();
+ autocompleteIndex = Math.min(autocompleteIndex + 1, autocompleteFiltered.length - 1);
+ renderAutocomplete();
+ } else if (event.key === 'ArrowUp') {
+ event.preventDefault();
+ autocompleteIndex = Math.max(autocompleteIndex - 1, -1);
+ renderAutocomplete();
+ } else if (event.key === 'Enter') {
+ event.preventDefault();
+ if (autocompleteIndex >= 0 && autocompleteIndex < autocompleteFiltered.length) {
+ selectAutocompleteItemBOM(autocompleteIndex, rowIdx);
+ }
+ } else if (event.key === 'Escape') {
+ hideAutocomplete();
+ }
+}
+
+function selectAutocompleteItemBOM(index, rowIdx) {
+ const comp = autocompleteFiltered[index];
+ if (!comp) return;
+ const row = bomRows.find(r => r.source_row_index === rowIdx) || bomRows[rowIdx];
+ if (!row) return;
+ row.manual_lot = comp.lot_name;
+ hideAutocomplete();
+ resolveBOM();
+}
+
function clearSingleSelect(category) {
cart = cart.filter(item =>
(item.category || getCategoryFromLotName(item.lot_name)).toUpperCase() !== category.toUpperCase()
@@ -2968,6 +3126,18 @@ function deleteBOMRawRow(rowIdx) {
rebuildBOMRowsFromRaw();
}
+function clearBOMLotMapping(rowIdx) {
+ const row = bomRows.find(r => r.source_row_index === rowIdx);
+ if (!row) return;
+ row.manual_lot = '';
+ row.resolved_lot = '';
+ row.resolution_source = 'unresolved';
+ row.lot_allocations = [];
+ row.bundle_enabled = false;
+ renderBOMTable();
+ debouncedResolveBOM();
+}
+
function _bomRawLotCell(rowIdx) {
if (!bomImportRaw || bomImportRaw.mode !== 'raw') return '—';
if (bomImportRaw.ignoredRows?.[rowIdx]) return '—';
@@ -2989,13 +3159,12 @@ function _bomRawLotCell(rowIdx) {
if (isUnresolved) {
const val = map.manual_lot || '';
- const invalid = val && !_bomLotValid(val);
- return `
+ return `
${renderBOMLotAllocationsEditor(rowIdx)}`;
}
let suffix = '';
@@ -3379,12 +3548,12 @@ function _renderBOMParsedTable() {
let lotCell = '';
if (isUnresolved) {
- lotCell = `${renderBOMLotAllocationsEditor(idx)}`;
+ lotCell = `${renderBOMLotAllocationsEditor(idx)}`;
} else {
let suffix = '';
if (qtyMismatch) suffix = ` ≠est(${cartQty})`;
@@ -3474,7 +3643,7 @@ function _renderBOMRawTable() {
|
-
+
| `;
tbody.appendChild(tr);
});