supplierlink3/create_supplier_order.php

466 lines
18 KiB
PHP
Executable file

<?php
/* Copyright (C) 2025 Eduard Wisch <data@data-it-solution.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
// Load Dolibarr environment
$res = 0;
if (!$res && file_exists("../main.inc.php")) $res = @include "../main.inc.php";
if (!$res && file_exists("../../main.inc.php")) $res = @include "../../main.inc.php";
if (!$res && file_exists("../../../main.inc.php")) $res = @include "../../../main.inc.php";
if (!$res && file_exists("../../../../main.inc.php")) $res = @include "../../../../main.inc.php";
if (!$res) die("Include of main fails");
require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/functions.lib.php';
$langs->loadLangs(array('orders', 'sendings', 'companies', 'suppliers'));
// Parameter
$origin = GETPOST('origin', 'alpha');
$originid = GETPOST('originid', 'int');
$action = GETPOST('action', 'alpha');
// Berechtigungen prüfen
if (empty($user->rights->fournisseur->commande->creer)) {
accessforbidden();
}
// Kundenauftrag laden
$objectsrc = new Commande($db);
$objectsrc->fetch($originid);
$objectsrc->fetch_lines();
// Kunde laden für Lieferantenreferenz
$customer = new Societe($db);
$customer->fetch($objectsrc->socid);
// Lieferantenreferenz Format: "Kundenname - Auftragsnummer / Kundenzeichen"
$supplier_ref_default = $customer->name.' - '.$objectsrc->ref;
if (!empty($objectsrc->ref_client)) {
$supplier_ref_default .= ' / '.$objectsrc->ref_client;
}
/*
* Actions
*/
if ($action == 'create_supplier_orders') {
$toselect = GETPOST('toselect', 'array');
$supplier_id = GETPOST('supplier_id', 'int');
$ref_supplier = GETPOST('ref_supplier', 'alpha');
if (empty($toselect)) {
setEventMessages('Bitte wählen Sie mindestens eine Zeile aus.', null, 'errors');
} elseif (empty($supplier_id)) {
setEventMessages('Bitte wählen Sie einen Lieferanten aus.', null, 'errors');
} else {
// Lieferantenbestellung erstellen
$supplierorder = new CommandeFournisseur($db);
$supplierorder->socid = $supplier_id;
$supplierorder->ref_supplier = !empty($ref_supplier) ? $ref_supplier : $supplier_ref_default;
$supplierorder->cond_reglement_id = 0;
$supplierorder->mode_reglement_id = 0;
$supplierorder->origin = 'commande';
$supplierorder->origin_id = $originid;
$db->begin();
$result = $supplierorder->create($user);
if ($result > 0) {
// Zeilen hinzufügen
$errors = 0;
foreach ($toselect as $lineid) {
// Zeile aus Kundenauftrag finden
$srcline = null;
foreach ($objectsrc->lines as $line) {
if ($line->id == $lineid) {
$srcline = $line;
break;
}
}
if ($srcline) {
$fournprice = 0;
$fournref = '';
$fournpricerowid = 0;
// Für Produkte: Günstigsten Lieferantenpreis für diesen Lieferanten finden
if (!empty($srcline->fk_product)) {
$sql = "SELECT pfp.rowid, pfp.ref_fourn, pfp.price, pfp.quantity as min_qty
FROM ".MAIN_DB_PREFIX."product_fournisseur_price pfp
WHERE pfp.fk_product = ".(int)$srcline->fk_product."
AND pfp.fk_soc = ".(int)$supplier_id."
ORDER BY pfp.price ASC
LIMIT 1";
$resql = $db->query($sql);
if ($resql && $db->num_rows($resql) > 0) {
$objprice = $db->fetch_object($resql);
$fournprice = $objprice->price;
$fournref = $objprice->ref_fourn;
$fournpricerowid = $objprice->rowid;
}
}
// Beschreibung für Freitext-Zeilen mit Hinweis versehen
$desc = $srcline->desc;
if (empty($srcline->fk_product)) {
$desc = "[FREITEXT - Produkt noch zuordnen]\n".$srcline->desc;
}
// Zeile zur Lieferantenbestellung hinzufügen
$result_line = $supplierorder->addline(
$desc, // Description
$fournprice, // Unit price
$srcline->qty, // Quantity
$srcline->tva_tx, // VAT rate
$srcline->localtax1_tx, // Local tax 1
$srcline->localtax2_tx, // Local tax 2
$srcline->fk_product, // Product ID (0 für Freitext)
$fournpricerowid, // Supplier price ID
$fournref, // Supplier ref
$srcline->remise_percent, // Discount
'HT', // Price base type
0, // pu_ht_devise
$srcline->product_type, // type (0=Produkt, 1=Dienstleistung)
0, // info_bits
false, // notrigger
null, // date_start
null, // date_end
0, // array_options
'', // fk_unit
0, // origin
0, // origin_id
1 // rang
);
if ($result_line < 0) {
$errors++;
}
}
}
if ($errors == 0) {
$db->commit();
setEventMessages('Lieferantenbestellung '.$supplierorder->ref.' wurde erstellt.', null, 'mesgs');
header('Location: '.DOL_URL_ROOT.'/fourn/commande/card.php?id='.$supplierorder->id);
exit;
} else {
$db->rollback();
setEventMessages('Fehler beim Hinzufügen der Zeilen.', null, 'errors');
}
} else {
$db->rollback();
setEventMessages('Fehler beim Erstellen der Lieferantenbestellung: '.$supplierorder->error, null, 'errors');
}
}
}
/*
* View
*/
$title = 'Lieferantenbestellung aus Kundenauftrag erstellen';
llxHeader('', $title);
print load_fiche_titre($title, '', 'order');
// Formular für Auswahl
print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="action" value="create_supplier_orders">';
print '<input type="hidden" name="origin" value="'.$origin.'">';
print '<input type="hidden" name="originid" value="'.$originid.'">';
// Zwei Boxen nebeneinander
print '<div class="fichecenter">';
// Linke Box: Kundenauftrag-Info
print '<div class="fichehalfleft">';
print '<div class="underbanner clearboth"></div>';
print '<table class="border centpercent tableforfield">';
print '<tr class="liste_titre"><th colspan="2">Kundenauftrag</th></tr>';
print '<tr class="oddeven"><td class="titlefield">'.$langs->trans("Ref").'</td>';
print '<td>'.$objectsrc->getNomUrl(1).'</td></tr>';
print '<tr class="oddeven"><td>'.$langs->trans("Customer").'</td>';
print '<td>'.$customer->getNomUrl(1).'</td></tr>';
print '<tr class="oddeven"><td>'.$langs->trans("RefCustomer").'</td>';
print '<td>'.dol_escape_htmltag($objectsrc->ref_client).'</td></tr>';
print '<tr class="oddeven"><td>'.$langs->trans("Status").'</td>';
print '<td>'.$objectsrc->getLibStatut(4).'</td></tr>';
print '</table>';
print '</div>';
// Rechte Box: Lieferant und Referenz
print '<div class="fichehalfright">';
print '<div class="underbanner clearboth"></div>';
print '<table class="border centpercent tableforfield">';
print '<tr class="liste_titre"><th colspan="2">Neue Lieferantenbestellung</th></tr>';
// Prüfen ob Produkte im Auftrag sind
$sqlCheckProducts = "SELECT COUNT(*) as nb FROM ".MAIN_DB_PREFIX."commandedet
WHERE fk_commande = ".(int)$originid." AND fk_product > 0";
$resCheckProducts = $db->query($sqlCheckProducts);
$hasProducts = false;
if ($resCheckProducts) {
$objCheck = $db->fetch_object($resCheckProducts);
$hasProducts = ($objCheck->nb > 0);
}
// Automatische Lieferanten: Nur die, die Produkte aus diesem Auftrag liefern können
$autoSuppliers = array();
if ($hasProducts) {
$sql = "SELECT DISTINCT s.rowid, s.nom
FROM ".MAIN_DB_PREFIX."societe s
INNER JOIN ".MAIN_DB_PREFIX."product_fournisseur_price pfp ON pfp.fk_soc = s.rowid
WHERE pfp.fk_product IN (
SELECT cd.fk_product FROM ".MAIN_DB_PREFIX."commandedet cd
WHERE cd.fk_commande = ".(int)$originid." AND cd.fk_product > 0
)
AND s.fournisseur = 1
ORDER BY s.nom ASC";
$resql = $db->query($sql);
if ($resql) {
while ($obj = $db->fetch_object($resql)) {
$autoSuppliers[$obj->rowid] = $obj->nom;
}
}
}
// Manuelle Lieferanten: Alle Lieferanten
$manualSuppliers = array();
$sql = "SELECT s.rowid, s.nom
FROM ".MAIN_DB_PREFIX."societe s
WHERE s.fournisseur > 0
ORDER BY s.nom ASC";
$resql = $db->query($sql);
if ($resql) {
while ($obj = $db->fetch_object($resql)) {
$manualSuppliers[$obj->rowid] = $obj->nom;
}
}
// Wenn keine automatischen Lieferanten, Standard auf manuell
$defaultMode = !empty($autoSuppliers) ? 'auto' : 'manual';
// Auswahl-Modus
print '<tr class="oddeven"><td class="titlefield">Lieferanten-Auswahl</td>';
print '<td>';
print '<label style="margin-right: 15px;"><input type="radio" name="supplier_mode" value="auto" id="mode_auto"'.($defaultMode == 'auto' ? ' checked' : '').(!empty($autoSuppliers) ? '' : ' disabled').'> Automatisch <span class="opacitymedium">('.count($autoSuppliers).' passende)</span></label>';
print '<label><input type="radio" name="supplier_mode" value="manual" id="mode_manual"'.($defaultMode == 'manual' ? ' checked' : '').'> Manuell <span class="opacitymedium">(alle '.count($manualSuppliers).' Lieferanten)</span></label>';
print '</td></tr>';
print '<tr class="oddeven"><td class="titlefield fieldrequired">Lieferant</td>';
print '<td><select name="supplier_id" id="supplier_id" class="flat maxwidth300" required>';
print '<option value="">-- Lieferant wählen --</option>';
// Beide Listen als data-Attribute für JavaScript speichern
print '</select>';
// Hidden divs mit den Optionen für JavaScript
print '<div id="autoSupplierOptions" style="display:none;">';
foreach ($autoSuppliers as $id => $name) {
print '<span data-id="'.$id.'">'.dol_escape_htmltag($name).'</span>';
}
print '</div>';
print '<div id="manualSupplierOptions" style="display:none;">';
foreach ($manualSuppliers as $id => $name) {
print '<span data-id="'.$id.'">'.dol_escape_htmltag($name).'</span>';
}
print '</div>';
print '</td></tr>';
// JavaScript für Modus-Umschaltung
print '<script type="text/javascript">
function updateSupplierDropdown() {
var mode = document.querySelector(\'input[name="supplier_mode"]:checked\').value;
var select = document.getElementById("supplier_id");
var sourceDiv = (mode == "auto") ? document.getElementById("autoSupplierOptions") : document.getElementById("manualSupplierOptions");
// Dropdown leeren
select.innerHTML = \'<option value="">-- Lieferant wählen --</option>\';
// Optionen aus dem entsprechenden div laden
var spans = sourceDiv.getElementsByTagName("span");
for (var i = 0; i < spans.length; i++) {
var option = document.createElement("option");
option.value = spans[i].getAttribute("data-id");
option.text = spans[i].textContent;
select.appendChild(option);
}
}
// Event-Listener für Radio-Buttons
document.getElementById("mode_auto").addEventListener("change", updateSupplierDropdown);
document.getElementById("mode_manual").addEventListener("change", updateSupplierDropdown);
// Initial laden
document.addEventListener("DOMContentLoaded", updateSupplierDropdown);
</script>';
print '<tr class="oddeven"><td>Lieferanten-Referenz</td>';
print '<td><input type="text" name="ref_supplier" value="'.dol_escape_htmltag($supplier_ref_default).'" class="flat quatrevingtpercent" placeholder="Kunde - Auftrag / Zeichen">';
print '</td></tr>';
print '</table>';
print '</div>'; // Ende fichehalfright
print '</div>'; // Ende fichecenter
print '<div class="clearboth"></div>';
print '<br>';
// Zeilen-Auswahl mit Checkboxen
print '<div class="div-table-responsive-no-min">';
print '<table class="noborder centpercent" id="tablelines">';
print '<tr class="liste_titre">';
print '<th class="center" style="width: 30px;"><input type="checkbox" id="checkall" onclick="toggleAll(this)"></th>';
print '<th>Produkt</th>';
print '<th class="right">Menge</th>';
print '<th class="right">Lagerbestand</th>';
print '<th colspan="2">Lieferanten</th>';
print '</tr>';
// Zeilen aus Kundenauftrag auflisten (Produkte und Freitext)
foreach ($objectsrc->lines as $line) {
// Dienstleistungen überspringen (nur Produkte und Freitext)
if (!empty($line->fk_product) && $line->product_type != 0) {
continue;
}
$isFreitext = empty($line->fk_product);
$product = null;
$qtyStock = 0;
$stockClass = '';
$supplierList = array();
if (!$isFreitext) {
// Produkt laden
$product = new Product($db);
$product->fetch($line->fk_product);
// Lagerbestand
$qtyStock = $product->stock_reel;
// Stock-Badge Farbe
$stockClass = 'badge-success';
if ($qtyStock <= 0) {
$stockClass = 'badge-danger';
} elseif ($product->seuil_stock_alerte > 0 && $qtyStock < $product->seuil_stock_alerte) {
$stockClass = 'badge-warning';
} elseif ($product->desiredstock > 0 && $qtyStock < $product->desiredstock) {
$stockClass = 'badge-secondary';
}
// Lieferanten für dieses Produkt
$sql_suppliers = "SELECT pfp.fk_soc, pfp.price, pfp.ref_fourn, s.nom
FROM ".MAIN_DB_PREFIX."product_fournisseur_price pfp
INNER JOIN ".MAIN_DB_PREFIX."societe s ON s.rowid = pfp.fk_soc
WHERE pfp.fk_product = ".(int)$line->fk_product."
ORDER BY pfp.price ASC";
$ressuppliers = $db->query($sql_suppliers);
if ($ressuppliers) {
while ($objsup = $db->fetch_object($ressuppliers)) {
$supplierList[] = dol_escape_htmltag($objsup->nom).' ('.number_format($objsup->price, 2, ',', '.').' EUR)';
}
}
}
print '<tr class="oddeven'.($isFreitext ? ' freitext-row' : '').'">';
// Checkbox
print '<td class="center">';
print '<input type="checkbox" name="toselect[]" value="'.$line->id.'" class="linecheckbox">';
print '</td>';
// Produkt oder Freitext
print '<td>';
if ($isFreitext) {
print '<span class="badge badge-info" style="margin-right: 5px;">FREITEXT</span>';
// Beschreibung anzeigen (gekürzt wenn zu lang)
$desc = dol_string_nohtmltag($line->desc);
if (strlen($desc) > 100) {
$desc = substr($desc, 0, 100).'...';
}
print '<em>'.dol_escape_htmltag($desc).'</em>';
} else {
print $product->getNomUrl(1);
print ' - '.dol_escape_htmltag($product->label);
}
print '</td>';
// Menge
print '<td class="right">'.(int)$line->qty.'</td>';
// Lagerbestand
print '<td class="right">';
if ($isFreitext) {
print '<span class="opacitymedium">-</span>';
} else {
print '<span class="badge '.$stockClass.'">'.(int)$qtyStock.'</span>';
}
print '</td>';
// Lieferanten
print '<td>';
if ($isFreitext) {
print '<span class="opacitymedium">Produkt manuell zuordnen</span>';
} elseif (!empty($supplierList)) {
print implode('<br>', $supplierList);
} else {
print '<span class="opacitymedium">Keine Lieferanten</span>';
}
print '</td>';
print '</tr>';
}
print '</table>';
print '</div>';
// Buttons
print '<div class="center" style="margin-top: 20px;">';
print '<input type="submit" class="button button-save" value="Lieferantenbestellung erstellen">';
print ' &nbsp; ';
print '<a class="button button-cancel" href="'.DOL_URL_ROOT.'/commande/card.php?id='.$originid.'">Abbrechen</a>';
print '</div>';
print '</form>';
// JavaScript für "Alle auswählen"
print '<script type="text/javascript">
function toggleAll(checkbox) {
var checkboxes = document.getElementsByClassName("linecheckbox");
for (var i = 0; i < checkboxes.length; i++) {
checkboxes[i].checked = checkbox.checked;
}
}
</script>';
// Badge-Styles
print '<style>
.badge.badge-danger { background-color: #dc3545 !important; color: #fff !important; }
.badge.badge-warning { background-color: #fd7e14 !important; color: #fff !important; }
.badge.badge-secondary { background-color: #6c757d !important; color: #fff !important; }
.badge.badge-success { background-color: #28a745 !important; color: #fff !important; }
.badge.badge-info { background-color: #17a2b8 !important; color: #fff !important; }
.freitext-row { background-color: #fff3cd !important; }
</style>';
llxFooter();
$db->close();