dolibarr.idsconnect/launch.php
data 81646f5ea4 feat(launch): Konfigurationsvalidierung & GlobalNotify-Integration v3.4
- Neue Funktion idsconnect_notify() für GlobalNotify-Benachrichtigungen
  mit Fallback auf dol_syslog falls Modul nicht installiert
- Neue Funktion idsconnect_validateSupplierConfig() prüft Supplier-
  Konfiguration vor dem Launch auf Vollständigkeit
- launch.php: Validierung vor Formular-Submit
  - Fehler (leeres Passwort): blockiert Launch, Redirect zur Konfiguration
  - Warnung (leerer Username): erlaubt Launch aber warnt User + Admin
- Löst Problem: Klux "Weiter"-Button fehlte weil ids_username leer war,
  Login schlug still fehl ohne jede Fehlermeldung

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-17 12:58:23 +01:00

320 lines
11 KiB
PHP
Executable file

<?php
/* Copyright (C) 2026 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.
*/
/**
* \file idsconnect/launch.php
* \ingroup idsconnect
* \brief Launcher - generiert und sendet IDS Connect Formular zum Großhandels-Shop
*/
// Dolibarr laden
$res = 0;
if (!$res && !empty($_SERVER["CONTEXT_DOCUMENT_ROOT"])) {
$res = @include $_SERVER["CONTEXT_DOCUMENT_ROOT"]."/main.inc.php";
}
$tmp = empty($_SERVER['SCRIPT_FILENAME']) ? '' : $_SERVER['SCRIPT_FILENAME'];
$tmp2 = realpath(__FILE__);
$i = strlen($tmp) - 1;
$j = strlen($tmp2) - 1;
while ($i > 0 && $j > 0 && isset($tmp[$i]) && isset($tmp2[$j]) && $tmp[$i] == $tmp2[$j]) {
$i--;
$j--;
}
if (!$res && $i > 0 && file_exists(substr($tmp, 0, ($i + 1))."/main.inc.php")) {
$res = @include substr($tmp, 0, ($i + 1))."/main.inc.php";
}
if (!$res && $i > 0 && file_exists(dirname(substr($tmp, 0, ($i + 1)))."/main.inc.php")) {
$res = @include dirname(substr($tmp, 0, ($i + 1)))."/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");
}
dol_include_once('/idsconnect/class/idsconnect.class.php');
dol_include_once('/idsconnect/class/idssupplier.class.php');
dol_include_once('/idsconnect/lib/idsconnect.lib.php');
/**
* @var Conf $conf
* @var DoliDB $db
* @var Translate $langs
* @var User $user
*/
$langs->loadLangs(array("idsconnect@idsconnect"));
// Berechtigungsprüfung
if (!$user->hasRight('idsconnect', 'use')) {
accessforbidden();
}
// Parameter
$supplier_id = GETPOSTINT('supplier_id');
$action = GETPOST('ids_action', 'alpha');
$confirm = GETPOST('confirm', 'alpha');
$confirm_wks = GETPOST('confirm_wks', 'alpha');
$fk_commande = GETPOSTINT('fk_commande');
// Validierung
if (empty($supplier_id) || empty($action)) {
setEventMessages($langs->trans("IdsconnectMissingParams"), null, 'errors');
header('Location: '.DOL_URL_ROOT.'/custom/idsconnect/idsconnectindex.php');
exit;
}
// CSRF-Schutz für den Launch
if (!verifCond(GETPOST('token', 'alpha') == newToken())) {
accessforbidden('Bad CSRF token');
}
// Großhändler laden
$supplier = new IdsSupplier($db);
$result = $supplier->fetch($supplier_id);
if ($result <= 0) {
setEventMessages($langs->trans("IdsconnectSupplierNotFound"), null, 'errors');
header('Location: '.DOL_URL_ROOT.'/custom/idsconnect/idsconnectindex.php');
exit;
}
// Prüfen ob der Großhändler aktiv ist
if (!$supplier->active) {
setEventMessages($langs->trans("IdsconnectSupplierInactive"), null, 'errors');
header('Location: '.DOL_URL_ROOT.'/custom/idsconnect/idsconnectindex.php');
exit;
}
// Supplier-Konfiguration auf Vollständigkeit prüfen
$config_issues = idsconnect_validateSupplierConfig($supplier);
$supplier_config_url = dol_buildpath('/idsconnect/supplier_card.php?id='.$supplier_id, 1);
foreach ($config_issues['errors'] as $err) {
setEventMessages($err, null, 'errors');
idsconnect_notify('action', 'IDS Connect: Konfigurationsfehler', $err, $supplier_config_url, 'Konfiguration öffnen');
}
foreach ($config_issues['warnings'] as $warn) {
setEventMessages($warn, null, 'warnings');
idsconnect_notify('warning', 'IDS Connect: Konfiguration unvollständig', $warn, $supplier_config_url, 'Konfiguration öffnen');
}
if (!empty($config_issues['errors'])) {
header('Location: '.$supplier_config_url);
exit;
}
// IDS Connect initialisieren
$idsconnect = new IdsConnect($db);
$testmode = $idsconnect->isTestMode($supplier);
// Bestätigungsseite bei Live-Modus (extra Sicherheit)
if (!$testmode && $confirm !== 'yes') {
llxHeader('', $langs->trans("IdsconnectLaunchConfirm"));
print '<div class="confirmmessage">';
print '<h2>'.$langs->trans("IdsconnectLaunchConfirmTitle").'</h2>';
print '<p><strong>'.$langs->trans("IdsconnectLaunchConfirmWarning").'</strong></p>';
print '<p>'.$langs->trans("IdsconnectLaunchConfirmText", $supplier->label, $action).'</p>';
print '<br>';
$confirm_url = $_SERVER['PHP_SELF'].'?supplier_id='.$supplier_id.'&ids_action='.urlencode($action).'&confirm=yes&token='.newToken();
if ($fk_commande > 0) {
$confirm_url .= '&fk_commande='.$fk_commande;
}
print '<a class="butAction" href="'.$confirm_url.'">'.$langs->trans("Confirm").'</a>';
print ' &nbsp; ';
print '<a class="butActionDelete" href="'.DOL_URL_ROOT.'/custom/idsconnect/idsconnectindex.php">'.$langs->trans("Cancel").'</a>';
print '</div>';
llxFooter();
$db->close();
exit;
}
// Zusätzliche Parameter sammeln
$extra = array();
if (!empty(GETPOST('artikelnr', 'alphanohtml'))) {
$extra['artikelnr'] = GETPOST('artikelnr', 'alphanohtml');
}
if (!empty(GETPOST('target', 'alpha'))) {
$extra['target'] = GETPOST('target', 'alpha');
}
// Bei WKS: Bestellpositionen aus Dolibarr-Bestellung als Warenkorb-XML generieren
$cart_lines = array();
if ($action === 'WKS' && $fk_commande > 0) {
require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
$order = new CommandeFournisseur($db);
$order->fetch($fk_commande);
$order->fetch_lines();
if (count($order->lines) > 0) {
$cart_lines = array();
foreach ($order->lines as $line) {
$cart_lines[] = array(
'artikelnr' => $line->ref_supplier ?: ($line->product_ref ?: ''),
'bezeichnung' => $line->desc ?: ($line->product_label ?: ''),
'menge' => $line->qty,
'einheit' => 'PCE',
'einzelpreis' => $line->subprice,
'mwst_satz' => $line->tva_tx,
);
}
$extra['warenkorb'] = $idsconnect->buildCartXml($cart_lines);
} else {
setEventMessages('Bestellung hat keine Positionen', null, 'errors');
header('Location: '.DOL_URL_ROOT.'/fourn/commande/card.php?id='.$fk_commande);
exit;
}
} elseif (!empty(GETPOST('warenkorb', 'none'))) {
$extra['warenkorb'] = GETPOST('warenkorb', 'none');
}
// WKS-PIN prüfen wenn Bestätigung kommt
if ($action === 'WKS' && $confirm_wks === 'yes') {
$stored_hash = getDolGlobalString('IDSCONNECT_WKS_PIN');
if (!empty($stored_hash)) {
$pin = GETPOST('wks_pin', 'none');
if (empty($pin) || !password_verify($pin, $stored_hash)) {
setEventMessages($langs->trans("IdsconnectWksPinWrong"), null, 'errors');
$confirm_wks = ''; // Bestätigungsseite erneut zeigen
}
}
}
// WKS-Bestätigung: Bestellinhalt prüfen bevor gesendet wird
if ($action === 'WKS' && !empty($cart_lines) && $confirm_wks !== 'yes') {
$wks_warn_qty = getDolGlobalInt('IDSCONNECT_WKS_WARN_QTY', 100);
$wks_warn_value = (float) getDolGlobalString('IDSCONNECT_WKS_WARN_VALUE', '10000');
llxHeader('', $langs->trans("IdsconnectWksConfirmTitle"), '', '', 0, 0, '', '', '', 'mod-idsconnect page-wks_confirm');
print load_fiche_titre($langs->trans("IdsconnectWksConfirmTitle"), '', 'fa-paper-plane');
idsconnectShowTestModeBanner();
// Info-Box
print '<div class="info">';
print '<strong>'.$langs->trans("IdsconnectWksConfirmInfo", $supplier->label).'</strong>';
print '</div>';
// Artikeltabelle
print '<table class="noborder centpercent">';
print '<tr class="liste_titre">';
print '<th>'.$langs->trans("IdsconnectCartArticleNr").'</th>';
print '<th>'.$langs->trans("IdsconnectCartDescription").'</th>';
print '<th class="right">'.$langs->trans("IdsconnectCartQty").'</th>';
print '<th>'.$langs->trans("IdsconnectCartUnit").'</th>';
print '<th class="right">'.$langs->trans("IdsconnectCartUnitPrice").'</th>';
print '<th class="right">'.$langs->trans("IdsconnectCartTotalPrice").'</th>';
print '</tr>';
$total = 0;
$warnings = array();
foreach ($cart_lines as $item) {
$line_total = (float) $item['menge'] * (float) $item['einzelpreis'];
$total += $line_total;
$qty_warn = ((float) $item['menge'] > $wks_warn_qty);
if ($qty_warn) {
$warnings[] = $langs->trans("IdsconnectWksWarnQtyLine", $item['artikelnr'], (float) $item['menge'], $wks_warn_qty);
}
print '<tr class="oddeven'.($qty_warn ? ' idsconnect-warn-row' : '').'">';
print '<td><code>'.htmlspecialchars($item['artikelnr']).'</code></td>';
print '<td>'.htmlspecialchars($item['bezeichnung']).'</td>';
print '<td class="right">'.($qty_warn ? '<strong class="idsconnect-warn-text">' : '').((float) $item['menge']).($qty_warn ? '</strong>' : '').'</td>';
print '<td>'.htmlspecialchars($item['einheit']).'</td>';
print '<td class="right">'.price($item['einzelpreis']).'</td>';
print '<td class="right">'.price($line_total).'</td>';
print '</tr>';
}
print '<tr class="liste_total">';
print '<td colspan="5" class="right"><strong>'.$langs->trans("Total").'</strong></td>';
print '<td class="right"><strong>'.price($total).'</strong></td>';
print '</tr>';
print '</table>';
// Wertwarnung
if ($total > $wks_warn_value) {
$warnings[] = $langs->trans("IdsconnectWksWarnValue", price($total), price($wks_warn_value));
}
// Warnungen anzeigen
if (!empty($warnings)) {
print '<div class="idsconnect-wks-warning">';
print '<strong>'.$langs->trans("IdsconnectWksWarningTitle").'</strong><br>';
foreach ($warnings as $w) {
print '- '.$w.'<br>';
}
print '</div>';
}
// Formular mit PIN-Eingabe und Absenden
print '<form method="POST" action="'.$_SERVER['PHP_SELF'].'">';
print '<input type="hidden" name="token" value="'.newToken().'">';
print '<input type="hidden" name="supplier_id" value="'.$supplier_id.'">';
print '<input type="hidden" name="ids_action" value="WKS">';
print '<input type="hidden" name="fk_commande" value="'.$fk_commande.'">';
print '<input type="hidden" name="confirm_wks" value="yes">';
if (!$testmode) {
print '<input type="hidden" name="confirm" value="yes">';
}
// PIN-Eingabe (wenn konfiguriert)
$has_pin = !empty(getDolGlobalString('IDSCONNECT_WKS_PIN'));
if ($has_pin) {
print '<div class="idsconnect-pin-box">';
print '<label><strong>'.$langs->trans("IdsconnectWksPin").':</strong></label> ';
print '<input type="password" name="wks_pin" required autocomplete="off" class="width100" placeholder="****">';
print ' <span class="opacitymedium">'.$langs->trans("IdsconnectWksPinInfo").'</span>';
print '</div>';
}
print '<div class="tabsAction">';
print '<input type="submit" class="butAction" value="'.$langs->trans("IdsconnectWksConfirmSend").'">';
print ' &nbsp; ';
print '<a class="butActionDelete" href="'.DOL_URL_ROOT.'/fourn/commande/card.php?id='.$fk_commande.'">'.$langs->trans("Cancel").'</a>';
print '</div>';
print '</form>';
llxFooter();
$db->close();
exit;
}
// Bei WKS: Bestellstatus auf "Bestellt" setzen
if ($action === 'WKS' && $fk_commande > 0 && isset($order) && $order->id > 0) {
if ($order->statut == CommandeFournisseur::STATUS_ACCEPTED) {
$order->commande($user, dol_now(), 0);
dol_syslog("IDS Connect: Bestellstatus auf 'Bestellt' gesetzt für Bestellung #".$order->id, LOG_INFO);
}
}
// Formular generieren
$result = $idsconnect->buildLaunchForm($supplier, $action, $user, $extra);
if ($result === false) {
setEventMessages($idsconnect->error, null, 'errors');
header('Location: '.DOL_URL_ROOT.'/custom/idsconnect/idsconnectindex.php');
exit;
}
// Testmodus-Hinweis loggen
if ($result['testmode']) {
dol_syslog("IDS Connect Launch: TESTMODUS aktiv - Verbindung geht zum Mock-Server", LOG_INFO);
}
// HTML-Formular direkt ausgeben (leitet zum Shop weiter)
header('Content-Type: text/html; charset=UTF-8');
echo $result['html'];
exit;