From 209ce1e3f8061e068f8234ee8491b558d80f8429 Mon Sep 17 00:00:00 2001 From: data Date: Fri, 30 Jan 2026 19:20:01 +0100 Subject: [PATCH] =?UTF-8?q?Version=202.1:=20Freitext-Zeilen=20Unterst?= =?UTF-8?q?=C3=BCtzung=20f=C3=BCr=20Lieferantenbestellungen?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Freitext-Zeilen aus Kundenaufträgen werden nun angezeigt und übernommen - Neue Lieferanten-Auswahl: Automatisch (passende) / Manuell (alle) - JavaScript-basierte Umschaltung ohne Seiten-Reload - Fallback für Systeme ohne markierte Lieferanten - Button erscheint nun auch bei reinen Freitext-Aufträgen Co-Authored-By: Claude Opus 4.5 --- class/actions_supplierlink3.class.php | 688 ++++++++++++++++++++---- core/modules/modSupplierLink3.class.php | 19 +- create_supplier_order.php | 466 ++++++++++++++++ js/replenish.js | 167 ++++++ langs/de_DE/supplierlink3.lang | 97 ++++ 5 files changed, 1331 insertions(+), 106 deletions(-) mode change 100755 => 100644 class/actions_supplierlink3.class.php mode change 100755 => 100644 core/modules/modSupplierLink3.class.php create mode 100644 create_supplier_order.php create mode 100644 js/replenish.js create mode 100644 langs/de_DE/supplierlink3.lang diff --git a/class/actions_supplierlink3.class.php b/class/actions_supplierlink3.class.php old mode 100755 new mode 100644 index 7634dc6..b39f01f --- a/class/actions_supplierlink3.class.php +++ b/class/actions_supplierlink3.class.php @@ -36,6 +36,16 @@ class ActionsSupplierLink3 extends CommonHookActions */ public $db; + /** + * @var int Debug mode (0=off, 1=on) + */ + private $debug = 0; + + /** + * @var string Debug log file path + */ + private $debugLogFile = '/tmp/supplierlink3_debug.log'; + /** * @var string Error code (or message) */ @@ -63,6 +73,16 @@ class ActionsSupplierLink3 extends CommonHookActions public $priority; + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + /** + * @var string Shop icon class (FontAwesome) + */ + private $shopIcon = 'fas fa-store'; + /** * Constructor * @@ -71,6 +91,38 @@ class ActionsSupplierLink3 extends CommonHookActions public function __construct($db) { $this->db = $db; + + // Debug-Modus aus Dolibarr-Konfiguration laden (Standard: AUS) + $this->debug = getDolGlobalInt('SUPPLIERLINK3_DEBUG_MODE', 0); + + // Shop-Icon aus Konfiguration laden + $this->shopIcon = getDolGlobalString('SUPPLIERLINK3_SHOP_ICON', 'fas fa-store'); + + // Nur loggen wenn Debug aktiviert + if ($this->debug) { + error_log('['.date('Y-m-d H:i:s').'] [CONSTRUCTOR] ActionsSupplierLink3 instanziiert'."\n", 3, $this->debugLogFile); + } + } + + /** + * Debug-Log schreiben + * + * @param string $message Nachricht + * @param string $method Methodenname + */ + private function debugLog($message, $method = '') + { + if (!$this->debug) { + return; + } + + $logLine = '['.date('Y-m-d H:i:s').']'; + if ($method) { + $logLine .= ' ['.$method.']'; + } + $logLine .= ' '.$message."\n"; + + error_log($logLine, 3, $this->debugLogFile); } @@ -401,111 +453,443 @@ class ActionsSupplierLink3 extends CommonHookActions return 1; }*/ /* Add other hook methods here... */ - public function printObjectLine($parameters, &$object, &$action, $hookmanager) + + /** + * Holt alle Lieferanten mit Shop-URL für ein Produkt + * + * @param int $fk_product Produkt-ID + * @return array Array mit Lieferanten-Daten, sortiert nach Preis aufsteigend + */ + private function getAllSuppliersForProduct($fk_product) + { + $suppliers = array(); + + $sql = "SELECT DISTINCT + pfp.fk_soc as supplier_id, + pfp.ref_fourn, + pfp.price, + pfp.quantity as min_qty, + s.nom as supplier_name, + se.shop_url + FROM ".MAIN_DB_PREFIX."product_fournisseur_price pfp + INNER JOIN ".MAIN_DB_PREFIX."societe s ON s.rowid = pfp.fk_soc + LEFT JOIN ".MAIN_DB_PREFIX."societe_extrafields se ON se.fk_object = pfp.fk_soc + WHERE pfp.fk_product = ".(int)$fk_product." + AND se.shop_url IS NOT NULL + AND se.shop_url != '' + ORDER BY pfp.price ASC"; + + $resql = $this->db->query($sql); + if ($resql) { + while ($obj = $this->db->fetch_object($resql)) { + $suppliers[] = array( + 'supplier_id' => $obj->supplier_id, + 'ref_fourn' => $obj->ref_fourn, + 'price' => $obj->price, + 'min_qty' => $obj->min_qty, + 'supplier_name' => $obj->supplier_name, + 'shop_url' => rtrim($obj->shop_url, '/'), + 'full_url' => rtrim($obj->shop_url, '/') . '/' . $obj->ref_fourn + ); + } + } + + return $suppliers; + } + + /** + * Generiert HTML-Badge für Lagerbestand + * + * 4 Zustände: + * - ROT: stock <= 0 (Nicht verfügbar) + * - ORANGE: stock < seuil_stock_alerte (Unter Mindestmenge) + * - GRAU: stock < desiredstock (Unter Wunschmenge) + * - GRÜN: stock >= desiredstock (Ausreichend) + * + * @param float $qtyStock Aktueller Lagerbestand + * @param float $desiredQty Wunschbestand + * @param float $alertQty Mindestbestand (seuil_stock_alerte) + * @return string HTML-Badge + */ + private function getStockBadgeHtml($qtyStock, $desiredQty, $alertQty = 0) + { + if ($qtyStock <= 0) { + // ROT: Nicht verfügbar (0 oder negativ) + $badgeClass = 'badge-danger'; + $icon = 'fa-times-circle'; + $tooltip = 'Nicht auf Lager'; + } elseif ($alertQty > 0 && $qtyStock < $alertQty) { + // ORANGE: Unter Mindestmenge (Alarm-Schwelle) + $badgeClass = 'badge-warning'; + $icon = 'fa-exclamation-triangle'; + $tooltip = 'Unter Mindestmenge ('.(int)$alertQty.')'; + } elseif ($desiredQty > 0 && $qtyStock < $desiredQty) { + // GRAU: Unter Wunschmenge + $badgeClass = 'badge-secondary'; + $icon = 'fa-box-open'; + $tooltip = 'Unter Wunschmenge ('.(int)$desiredQty.')'; + } else { + // GRÜN: Ausreichend auf Lager + $badgeClass = 'badge-success'; + $icon = 'fa-check-circle'; + $tooltip = 'Ausreichend auf Lager'; + } + + $html = ''; + $html .= ''; + $html .= number_format($qtyStock, 0, ',', '.'); + $html .= ''; + + return $html; + } + + /** + * Generiert Shop-Link HTML (Icon oder Modal-Trigger für mehrere Lieferanten) + * + * @param array $suppliers Array der Lieferanten + * @param int $currentSupplierId Aktueller Lieferant der Bestellung + * @param string $refFourn Lieferanten-Artikelnummer + * @param int $lineId Zeilen-ID für eindeutige Modal-ID + * @return string HTML für Shop-Link + */ + private function getShopLinkHtml($suppliers, $currentSupplierId, $refFourn, $lineId) + { + if (empty($suppliers)) { + return ''; + } + + // Fall 1: Nur ein Lieferant mit Shop-URL - direkter Link + if (count($suppliers) == 1) { + $supplier = $suppliers[0]; + $html = 'shopIcon.'">'; + $html .= ''; + return $html; + } + + // Fall 2: Mehrere Lieferanten - Modal-Trigger + $modalId = 'supplier_modal_'.$lineId; + + // Trigger-Button mit Dropdown-Pfeil + $html = 'shopIcon.'">'; + $html .= ''; + $html .= ''; + + // Modal-Container (versteckt) + $html .= '