diff --git a/web/templates/index.html b/web/templates/index.html
index 69d4e0e..8250d53 100644
--- a/web/templates/index.html
+++ b/web/templates/index.html
@@ -1656,6 +1656,10 @@ function renderAutocomplete() {
// Build autocomplete items based on mode
dropdown.innerHTML = autocompleteFiltered.map((comp, idx) => {
+ if (comp.isDivider) {
+ return `
── прочие ──
`;
+ }
+
let onmousedown;
if (autocompleteMode === 'section') {
@@ -2039,14 +2043,24 @@ function showAutocompleteBOM(rowIdx, input) {
function filterAutocompleteBOM(rowIdx, search) {
const searchLower = (search || '').toLowerCase();
- autocompleteFiltered = (window._bomAllComponents || allComponents).filter(c => {
+ const cartLots = new Set(cart.map(i => i.lot_name));
+ const all = (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);
});
+ const inCart = all.filter(c => cartLots.has(c.lot_name))
+ .sort((a, b) => a.lot_name.localeCompare(b.lot_name));
+ const notInCart = all.filter(c => !cartLots.has(c.lot_name))
+ .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);
+ });
+ if (inCart.length && notInCart.length) {
+ autocompleteFiltered = [...inCart, {isDivider: true}, ...notInCart];
+ } else {
+ autocompleteFiltered = [...inCart, ...notInCart];
+ }
renderAutocomplete();
}
@@ -2071,7 +2085,7 @@ function handleAutocompleteKeyBOM(event, rowIdx) {
function selectAutocompleteItemBOM(index, rowIdx) {
const comp = autocompleteFiltered[index];
- if (!comp) return;
+ if (!comp || comp.isDivider) return;
const row = bomRows.find(r => r.source_row_index === rowIdx) || bomRows[rowIdx];
if (!row) return;
row.manual_lot = comp.lot_name;
@@ -3209,7 +3223,7 @@ function _bomRawLotCell(rowIdx) {
cart.forEach(item => { cartMap[item.lot_name] = item.quantity; });
const isUnresolved = !map.resolved_lot || map.resolution_source === 'unresolved';
const cartQty = map.resolved_lot ? (cartMap[map.resolved_lot] ?? null) : null;
- const qtyMismatch = cartQty !== null && cartQty !== map.quantity;
+ const qtyMismatch = cartQty !== null && cartQty !== map.quantity * _getRowLotQtyPerPN(map);
const notInCart = map.resolved_lot && cartQty === null;
if (isUnresolved) {
@@ -3595,7 +3609,7 @@ function _renderBOMParsedTable() {
const tr = document.createElement('tr');
const isUnresolved = !row.resolved_lot || row.resolution_source === 'unresolved';
const cartQty = row.resolved_lot ? (cartMap[row.resolved_lot] ?? null) : null;
- const qtyMismatch = cartQty !== null && cartQty !== row.quantity;
+ const qtyMismatch = cartQty !== null && cartQty !== row.quantity * _getRowLotQtyPerPN(row);
const notInCart = row.resolved_lot && cartQty === null;
if (isUnresolved) unresolved++;
if (qtyMismatch || notInCart) mismatches++;
@@ -3662,7 +3676,7 @@ function _renderBOMRawTable() {
else if (parsed) {
const isUnresolved = !parsed.resolved_lot || parsed.resolution_source === 'unresolved';
const cartQty = parsed.resolved_lot ? (cartMap[parsed.resolved_lot] ?? null) : null;
- const qtyMismatch = cartQty !== null && cartQty !== parsed.quantity;
+ const qtyMismatch = cartQty !== null && cartQty !== parsed.quantity * _getRowLotQtyPerPN(parsed);
const notInCart = parsed.resolved_lot && cartQty === null;
if (isUnresolved) unresolved++;
if (qtyMismatch || notInCart) mismatches++;