diff --git a/CHANGELOG.md b/CHANGELOG.md index aabbc9b..da54be6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ # Changelog — ProductImageTags +## 0.1.1 (2026-06-18) + +### Behoben +- **Falsches Produktbild im Angebot.** Bilder wurden rein alphabetisch nach Dateiname + sortiert, dadurch landete „das erste Bild" willkürlich im PDF — nicht das, was im + Produktkärtchen als Hauptbild/erstes Bild angezeigt wird. `listSourceImages` liest + jetzt `position` und `cover` aus `llx_ecm_files` und sortiert exakt wie Dolibarrs + `Product::show_photos()`: Cover (Hauptbild) zuerst, dann Galerie-Position, dann + alphabetisch als Fallback. Nicht indexierte Dateien landen am Ende (Position 999999). + → Hauptbild per Drag&Drop an Position 1 ziehen oder als Cover markieren steuert jetzt, + welches Bild im Angebot erscheint. + ## 0.1.0 (2026-04-24) Erste lauffähige Version — Bilder erscheinen live in Angebots-/Auftrags-PDFs. diff --git a/class/productimage.class.php b/class/productimage.class.php index f022f12..fdaab04 100644 --- a/class/productimage.class.php +++ b/class/productimage.class.php @@ -167,18 +167,59 @@ class ProductImage return array(); } - // dol_dir_list sortiert stabil alphabetisch. Thumbnails (thumbs-Unterordner + _small/_mini-Suffixe) ausschließen. + // Thumbnails (thumbs-Unterordner + _small/_mini-Suffixe) ausschließen. $files = dol_dir_list($photoDir, 'files', 0, '', array('\.meta$', '_small\.', '_mini\.', '_preview'), 'name', SORT_ASC); if (empty($files)) { return array(); } - $result = array(); + // WICHTIG: Reihenfolge GENAU wie Dolibarr im Produktkärtchen (Product::show_photos + // sortiert nach position_name + cover aus der Tabelle ecm_files). Sortieren wir nur + // alphabetisch nach Dateiname, ist „das erste Bild" willkürlich und passt nicht zu + // dem, was der User als Hauptbild/erste Reihenfolge in der Bildergalerie sieht. + // Deshalb Position + Cover aus ecm_files lesen und danach sortieren: + // 1. Cover (manuell als Hauptbild markiert) zuerst + // 2. dann Position (per Drag&Drop in der Galerie festgelegt) + // 3. dann alphabetisch als Fallback (nicht indexierte Dateien ans Ende) + $relativedir = trim(preg_replace('#^'.preg_quote(DOL_DATA_ROOT, '#').'#', '', $photoDir), '/\\'); + $meta = array(); + $dbfiles = dol_dir_list_in_database($relativedir, '', null, 'name', SORT_ASC, 0, '', $product); + foreach ($dbfiles as $dbf) { + $meta[$dbf['name']] = array( + 'position' => (int) $dbf['position'], + 'cover' => (int) $dbf['cover'], + ); + } + + $indexed = array(); foreach ($files as $file) { $fullPath = $file['fullname']; - if (image_format_supported($fullPath) > 0) { - $result[] = $fullPath; + if (image_format_supported($fullPath) <= 0) { + continue; } + $name = $file['name']; + $indexed[] = array( + 'path' => $fullPath, + 'name' => $name, + 'cover' => isset($meta[$name]) ? $meta[$name]['cover'] : 0, + // Nicht indexierte Dateien ans Ende (Dolibarr-Konvention: position 999999) + 'position' => isset($meta[$name]) ? $meta[$name]['position'] : 999999, + ); + } + + usort($indexed, function ($a, $b) { + if ($a['cover'] !== $b['cover']) { + return $b['cover'] - $a['cover']; // cover=1 zuerst + } + if ($a['position'] !== $b['position']) { + return $a['position'] - $b['position']; + } + return strcasecmp($a['name'], $b['name']); + }); + + $result = array(); + foreach ($indexed as $row) { + $result[] = $row['path']; } return $result; }