/**
* 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);
});