/** * SupplierLink3 - Replenish page enhancements * Ersetzt die "Aktueller Lagerbestand"-Spalte mit Badge + Shop-Link * Version 2.3: Lagerbestand (Physisch|Theoretisch) wie Dolibarr Standard */ console.log('SL3: replenish.js loaded'); $(document).ready(function() { console.log('SL3: DOM ready, sl3Data exists:', typeof window.sl3Data !== 'undefined'); if (typeof window.sl3Data === 'undefined') { console.log('SL3: No data found, exiting'); return; } var productSuppliers = window.sl3Data; var shopIcon = window.sl3ShopIcon || 'fas fa-store'; console.log('SL3: Processing', Object.keys(productSuppliers).length, 'products'); // CSS einfügen $('head').append(''); // Modal-Handler mit Preisvergleich $(document).on('click', '.sl3-modal-trigger', function(e) { e.preventDefault(); var suppliers = $(this).data('suppliers'); if (!suppliers || suppliers.length === 0) return; var minPrice = suppliers[0].price; var content = ''; for (var i = 0; i < suppliers.length; i++) { var sup = suppliers[i]; var isFirst = (i === 0); var bgClass = isFirst ? 'cheapest' : ''; var star = isFirst ? '' : ''; // Prozentuale Differenz zum günstigsten var percentDiff = 0; var percentHtml = ''; if (minPrice > 0 && sup.price > minPrice) { percentDiff = ((sup.price - minPrice) / minPrice * 100).toFixed(1); var diffColor = percentDiff > 20 ? '#dc3545' : (percentDiff > 10 ? '#fd7e14' : '#6c757d'); percentHtml = '+' + percentDiff + '%'; } content += '
'; content += '
'; content += '' + star + sup.supplier_name + ''; content += percentHtml; content += '
'; content += '
'; content += '' + parseFloat(sup.price).toFixed(2).replace('.', ',') + ' EUR'; content += ' · ab ' + sup.min_qty + ' St.'; content += ' · Art.-Nr: ' + sup.ref_fourn; content += '
'; if (sup.full_url) { content += 'Im Shop öffnen'; } content += '
'; } $('
').html(content).dialog({ modal: true, title: 'Lieferanten-Vergleich', width: 420, buttons: { 'Schließen': function() { $(this).dialog('close'); } } }); }); // Spalten-Indizes aus der Header-Zeile ermitteln var colIndex = { stock: -1, desired: -1, alert: -1 }; $('table.liste tr.liste_titre th, table.liste tr.liste_titre td').each(function(idx) { var text = $(this).text().trim().toLowerCase(); // Stock-Spalte (Aktueller Lagerbestand / Physical stock / Physischer Bestand) if (text.indexOf('lagerbestand') >= 0 || text.indexOf('physical stock') >= 0 || text.indexOf('stock physique') >= 0 || text.indexOf('physischer bestand') >= 0) { colIndex.stock = idx; } // Desired Stock (Gewünschter Lagerbestand / Wunschbestand) if (text.indexOf('gewünscht') >= 0 || text.indexOf('wunsch') >= 0 || text.indexOf('desired') >= 0 || text.indexOf('souhaité') >= 0) { colIndex.desired = idx; } // Alert Stock (Grenzwert für Warnung / Mindestbestand / Stock limit) if (text.indexOf('grenzwert') >= 0 || text.indexOf('warnung') >= 0 || text.indexOf('mindest') >= 0 || text.indexOf('limit') >= 0 || text.indexOf('alerte') >= 0 || text.indexOf('alert') >= 0) { colIndex.alert = idx; } }); console.log('SL3: Column indices found:', colIndex); // Fallback auf feste Indizes wenn nicht gefunden if (colIndex.stock < 0) colIndex.stock = 5; if (colIndex.desired < 0) colIndex.desired = 3; if (colIndex.alert < 0) colIndex.alert = 4; // Jede Datenzeile in der Tabelle durchgehen var rowsFound = 0; var rowsProcessed = 0; $('table.liste tr').not('.liste_titre').each(function() { rowsFound++; var $row = $(this); // Produkt-Link finden um die Produkt-ID zu extrahieren var $productLink = $row.find('td a[href*="product/card.php?id="]').first(); if ($productLink.length === 0) { $productLink = $row.find('td a[href*="product.php?id="]').first(); } if ($productLink.length === 0) { return; } var href = $productLink.attr('href'); var match = href.match(/id=(\d+)/); if (!match) { return; } var productId = match[1]; rowsProcessed++; // Stock-Spalte dynamisch finden var $stockCell = $row.find('td').eq(colIndex.stock); if ($stockCell.length === 0) return; // Stock-Wert aus der Zelle lesen (physischer Bestand) var physicalStock = parseFloat($stockCell.text().trim()) || 0; // Desired-Stock und Alert-Stock var desired = parseFloat($row.find('td').eq(colIndex.desired).text().trim()) || 0; var alert = parseFloat($row.find('td').eq(colIndex.alert).text().trim()) || 0; // In der Replenish-Liste haben wir nur den physischen Bestand // Theoretischer Bestand wird hier gleich dem physischen gesetzt // (Der echte theoretische Bestand wird nur in den Orders angezeigt) var theoreticalStock = physicalStock; // Badge-Klasse basierend auf physischem Bestand var badgeClass = 'badge-success'; var icon = 'fa-check-circle'; var tooltip = 'Ausreichend verfügbar'; if (physicalStock < 1) { badgeClass = 'badge-danger'; icon = 'fa-times-circle'; tooltip = 'Nicht verfügbar'; } else if (alert > 0 && physicalStock <= alert) { badgeClass = 'badge-warning'; icon = 'fa-exclamation-triangle'; tooltip = 'Unter Mindestmenge (' + alert + ')'; } else if (desired > 0 && physicalStock < desired) { badgeClass = 'badge-secondary'; icon = 'fa-box-open'; tooltip = 'Unter Wunschmenge (' + desired + ')'; } // Shop-Link und günstigster Lieferant ermitteln var shopIconHtml = ''; var supplierBadgeHtml = ''; var suppliers = productSuppliers[productId]; if (suppliers && suppliers.length > 0) { // Günstigster Lieferant Badge var cheapest = suppliers[0]; var shortCode = cheapest.supplier_name.replace(/[^a-zA-Z0-9]/g, '').substring(0, 3).toUpperCase(); supplierBadgeHtml = '' + shortCode + ''; if (suppliers.length === 1) { shopIconHtml = '' + ''; } else { shopIconHtml = '' + ''; } } // Stock-Zelle ersetzen mit neuem Format: Physisch | Theoretisch var html = '
' + '' + shopIconHtml + '' + supplierBadgeHtml + '' + '' + '' + '' + Math.floor(physicalStock) + '' + '|' + '' + Math.floor(theoreticalStock) + '' + '' + '
'; $stockCell.html(html).addClass('right').css('text-align', 'right'); }); console.log('SL3: Processing complete - rows found:', rowsFound, 'rows processed:', rowsProcessed); });