diff --git a/ChangeLog.md b/ChangeLog.md index 40450f7..4e00490 100755 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -1,5 +1,19 @@ # CHANGELOG MODULE IMPORTZUGFERD FOR [DOLIBARR ERP CRM](https://www.dolibarr.org) +## 3.4 + +### Bugfixes +- Fehlende Lieferantenpreise: EAN-basierte Suche nutzt jetzt Barcode aus Lieferantenpreis statt Artikelnummer +- Fehlende Lieferantenpreise: Unique-Key auf Barcode entfernt (mehrere Lieferanten koennen gleichen EAN haben) +- Fehlende Lieferantenpreise: Variable $extrafields Namenskollision mit Dolibarr-Core behoben +- Fehlende Lieferantenpreise: Duplikate bei gleichen Produkten auf mehreren Rechnungszeilen vermieden +- Produktauswahl: select2-Suche funktioniert jetzt auf allen Zeilen (eindeutige HTML-IDs) + +### Verbesserungen +- Fehlende Lieferantenpreise in konsolidiertem Bereich unterhalb der Produkttabelle +- Refresh-Button fuer Produktlisten nach Anlage neuer Produkte +- Alle auswaehlen / Keine auswaehlen fuer fehlende Lieferantenpreise + ## 3.3 ### Sicherheit und Code-Qualitaet diff --git a/core/modules/modImportZugferd.class.php b/core/modules/modImportZugferd.class.php index 1a7eb6b..f4e8d9a 100755 --- a/core/modules/modImportZugferd.class.php +++ b/core/modules/modImportZugferd.class.php @@ -76,7 +76,7 @@ class modImportZugferd extends DolibarrModules $this->editor_squarred_logo = ''; // Must be image filename into the module/img directory followed with @modulename. Example: 'myimage.png@importzugferd' // Possible values for version are: 'development', 'experimental', 'dolibarr', 'dolibarr_deprecated', 'experimental_deprecated' or a version string like 'x.y.z' - $this->version = '3.3'; + $this->version = '3.4'; // Url to the file with your last numberversion of this module //$this->url_last_version = 'http://www.example.com/versionmodule.txt'; diff --git a/import.php b/import.php index f97b6c1..83eb27c 100755 --- a/import.php +++ b/import.php @@ -77,6 +77,13 @@ $supplier_id = GETPOST('supplier_id', 'int'); $line_id = GETPOST('line_id', 'int'); $product_id = GETPOST('product_id', 'int'); $template_product_id = GETPOST('template_product_id', 'int'); +// Zeilenspezifische Produkt-IDs (wegen eindeutiger select2-IDs pro Zeile) +if (empty($product_id) && $line_id > 0) { + $product_id = GETPOST('product_id_'.$line_id, 'int'); +} +if (empty($template_product_id) && $line_id > 0) { + $template_product_id = GETPOST('template_product_id_'.$line_id, 'int'); +} // Initialize objects $form = new Form($db); @@ -499,21 +506,34 @@ if ($action == 'removeproduct' && $line_id > 0) { $import->fetch($id); } -// Add missing supplier prices from other catalogs +// Fehlende Lieferantenpreise aus anderen Katalogen hinzufuegen if ($action == 'addmissingprices' && $id > 0) { $import->fetch($id); - $fk_product = GETPOSTINT('fk_product'); - $addSupplierPrices = GETPOST('add_supplier_prices', 'array'); - - if ($fk_product > 0 && !empty($addSupplierPrices)) { - require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.product.class.php'; - require_once './class/datanorm.class.php'; - require_once './class/productmapping.class.php'; + $selectedPrices = GETPOST('add_prices', 'array'); + if (!empty($selectedPrices)) { $addedCount = 0; + $processedKeys = array(); + + foreach ($selectedPrices as $entry) { + // Duplikate ueberspringen + if (isset($processedKeys[$entry])) { + continue; + } + $processedKeys[$entry] = true; + + $parts = explode(',', $entry); + if (count($parts) !== 3) { + continue; + } + $productId = (int) $parts[0]; + $socId = (int) $parts[1]; + $datanormId = (int) $parts[2]; + + if ($productId <= 0 || $socId <= 0 || $datanormId <= 0) { + continue; + } - foreach ($addSupplierPrices as $socId => $datanormId) { - // Fetch the Datanorm article $datanorm = new Datanorm($db); if ($datanorm->fetch($datanormId) > 0) { $altSupplier = new Societe($db); @@ -524,38 +544,16 @@ if ($action == 'addmissingprices' && $id > 0) { $purchasePrice = $datanorm->price / $datanorm->price_unit; } - // Prepare extrafields - $extrafields = array(); - if (!empty($datanorm->metal_surcharge) && $datanorm->metal_surcharge > 0) { - $extrafields['options_kupferzuschlag'] = $datanorm->metal_surcharge; - } - if (!empty($datanorm->price_unit) && $datanorm->price_unit > 1) { - $extrafields['options_preiseinheit'] = $datanorm->price_unit; - } - if (!empty($datanorm->product_group)) { - $extrafields['options_warengruppe'] = $datanorm->product_group; - } - - // Add supplier price - $prodfourn = new ProductFournisseur($db); - $prodfourn->id = $fk_product; - $result = $prodfourn->update_buyprice( - 1, $purchasePrice, $user, 'HT', $altSupplier, 0, - $datanorm->article_number, 19, - 0, 0, 0, 0, 0, 0, array(), '', - 0, 'HT', 1, '', - trim($datanorm->short_text1 . ($datanorm->short_text2 ? ' ' . $datanorm->short_text2 : '')), - !empty($datanorm->ean) ? $datanorm->ean : '', - !empty($datanorm->ean) ? 2 : 0, - $extrafields - ); + $priceExtrafields = datanormBuildSupplierPriceExtrafields($datanorm); + $result = datanormAddSupplierPrice($db, $productId, $datanorm, $altSupplier, $user, $purchasePrice, 19, $priceExtrafields); if ($result > 0) { - // Create product mapping + datanormInsertPriceExtrafields($db, $result, $priceExtrafields); + $mapping = new ProductMapping($db); $mapping->fk_soc = $socId; $mapping->supplier_ref = $datanorm->article_number; - $mapping->fk_product = $fk_product; + $mapping->fk_product = $productId; $mapping->ean = $datanorm->ean; $mapping->manufacturer_ref = $datanorm->manufacturer_ref; $mapping->description = $datanorm->short_text1; @@ -1968,6 +1966,7 @@ if ($action == 'edit' && $import->id > 0) { $allProductsMatched = true; $matchedLinesCount = 0; $totalLinesCount = count($lines); + $allMissingPrices = array(); // Fehlende Lieferantenpreise sammeln foreach ($lines as $line) { $hasProduct = ($line->fk_product > 0); @@ -2069,44 +2068,48 @@ if ($action == 'edit' && $import->id > 0) { print ''; print ''; - // Check for missing supplier prices from other catalogs + // Fehlende Lieferantenpreise aus anderen Katalogen sammeln (Anzeige weiter unten) if ($import->fk_soc > 0 && getDolGlobalString('IMPORTZUGFERD_DATANORM_SEARCH_ALL')) { - // Get existing supplier prices for this product - $sqlExistingPrices = "SELECT fk_soc FROM ".MAIN_DB_PREFIX."product_fournisseur_price"; + // Alle vorhandenen Lieferantenpreise fuer dieses Produkt laden + $sqlExistingPrices = "SELECT fk_soc, price, barcode FROM ".MAIN_DB_PREFIX."product_fournisseur_price"; $sqlExistingPrices .= " WHERE fk_product = ".(int)$line->fk_product; $resExistingPrices = $db->query($sqlExistingPrices); $existingSupplierIds = array(); + $currentSupplierPrice = 0; + $supplierEan = ''; if ($resExistingPrices) { while ($objPrice = $db->fetch_object($resExistingPrices)) { $existingSupplierIds[$objPrice->fk_soc] = true; + // Preis und EAN vom Rechnungslieferanten merken + if ($objPrice->fk_soc == $import->fk_soc) { + $currentSupplierPrice = $objPrice->price; + if (!empty($objPrice->barcode)) { + $supplierEan = $objPrice->barcode; + } + } } } - // Get current supplier price for comparison - $currentSupplierPrice = 0; - if (isset($existingSupplierIds[$import->fk_soc])) { - $sqlCurrentPrice = "SELECT price FROM ".MAIN_DB_PREFIX."product_fournisseur_price"; - $sqlCurrentPrice .= " WHERE fk_product = ".(int)$line->fk_product; - $sqlCurrentPrice .= " AND fk_soc = ".(int)$import->fk_soc; - $sqlCurrentPrice .= " ORDER BY unitprice ASC LIMIT 1"; - $resCurrentPrice = $db->query($sqlCurrentPrice); - if ($resCurrentPrice && $db->num_rows($resCurrentPrice) > 0) { - $objCurrentPrice = $db->fetch_object($resCurrentPrice); - $currentSupplierPrice = $objCurrentPrice->price; - } - } + // EAN-Quellen: 1. Lieferantenpreis-Barcode, 2. Import-Zeile EAN + $searchEan = !empty($supplierEan) ? $supplierEan : (!empty($line->ean) ? $line->ean : ''); - // Search in all Datanorm catalogs for this article $datanormSearch = new Datanorm($db); - $searchRef = !empty($line->supplier_ref) ? $line->supplier_ref : (!empty($line->ean) ? $line->ean : ''); - if (!empty($searchRef)) { - $allCatalogResults = $datanormSearch->searchByArticleNumber($searchRef, $import->fk_soc, true, 10); + $allCatalogResults = array(); + + // Primaer: EAN-Suche in Datanorm-Katalogen (zuverlaessigste Methode) + if (!empty($searchEan)) { + $allCatalogResults = $datanormSearch->searchByArticleNumber($searchEan, $import->fk_soc, true, 10); + } + // Fallback: Lieferanten-Artikelnummer wenn EAN nichts fand + if (empty($allCatalogResults) && !empty($line->supplier_ref)) { + $allCatalogResults = $datanormSearch->searchByArticleNumber($line->supplier_ref, $import->fk_soc, true, 10); + } + + if (!empty($allCatalogResults)) { - // Filter to only show suppliers without existing price $missingSuppliers = array(); foreach ($allCatalogResults as $catalogResult) { if (!isset($existingSupplierIds[$catalogResult['fk_soc']])) { - // Load supplier name $altSupplier = new Societe($db); $altSupplier->fetch($catalogResult['fk_soc']); @@ -2128,54 +2131,20 @@ if ($action == 'edit' && $import->id > 0) { } } - // Show missing suppliers with checkboxes if (!empty($missingSuppliers)) { - print '