- Menü unter Einkauf > Lieferantenbestellungen statt eigenes Top-Menü - ADL-Buttons auf Produkt-Lieferantenpreisen per Hook (pricesuppliercard) - Admin-Seite: Großhändler-Schnellübersicht mit Version-Check - Dashboard: Shop-öffnen-Button (LI-Action) - Neue Datei: class/actions_idsconnect.class.php Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
474 lines
18 KiB
PHP
Executable file
474 lines
18 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/callback.php
|
|
* \ingroup idsconnect
|
|
* \brief HOOKURL-Callback-Handler - empfängt Warenkörbe vom Großhandels-Shop
|
|
*/
|
|
|
|
// Version zur Überprüfung ob der richtige Code deployed ist
|
|
define('IDSCONNECT_CALLBACK_VERSION', '2.0');
|
|
|
|
// Dolibarr laden (ohne Login-Erfordernis für Callback)
|
|
define('NOLOGIN', 1);
|
|
define('NOCSRFCHECK', 1);
|
|
define('NOREQUIREMENU', 1);
|
|
define('NOREQUIREHTML', 1);
|
|
define('NOREQUIREAJAX', 1);
|
|
|
|
$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) {
|
|
http_response_code(500);
|
|
die("Server configuration error");
|
|
}
|
|
|
|
require_once DOL_DOCUMENT_ROOT.'/core/lib/security.lib.php';
|
|
dol_include_once('/idsconnect/class/idsconnect.class.php');
|
|
dol_include_once('/idsconnect/class/idslog.class.php');
|
|
dol_include_once('/idsconnect/class/idssupplier.class.php');
|
|
|
|
/**
|
|
* @var DoliDB $db
|
|
*/
|
|
|
|
// Callback-Eingang loggen (alles erfassen für Debugging)
|
|
$callback_meta = array(
|
|
'callback_version' => IDSCONNECT_CALLBACK_VERSION,
|
|
'method' => $_SERVER['REQUEST_METHOD'],
|
|
'remote_ip' => getUserRemoteIP(),
|
|
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'unbekannt',
|
|
'content_type' => $_SERVER['CONTENT_TYPE'] ?? 'unbekannt',
|
|
'content_length' => $_SERVER['CONTENT_LENGTH'] ?? 0,
|
|
'query_string' => $_SERVER['QUERY_STRING'] ?? '',
|
|
'post_keys' => array_keys($_POST),
|
|
'files_keys' => array_keys($_FILES),
|
|
'timestamp' => date('Y-m-d H:i:s'),
|
|
);
|
|
dol_syslog("IDS Connect Callback v".IDSCONNECT_CALLBACK_VERSION.": Eingang von ".$callback_meta['remote_ip']." Method=".$callback_meta['method']." POST-Keys=".implode(',', $callback_meta['post_keys'])." FILES-Keys=".implode(',', $callback_meta['files_keys']), LOG_INFO);
|
|
|
|
// Nur POST und GET erlauben
|
|
if (!in_array($_SERVER['REQUEST_METHOD'], array('POST', 'GET'))) {
|
|
dol_syslog("IDS Connect Callback: Method Not Allowed: ".$_SERVER['REQUEST_METHOD'], LOG_WARNING);
|
|
http_response_code(405);
|
|
die("Method not allowed");
|
|
}
|
|
|
|
// Token aus GET oder POST
|
|
$token = GETPOST('token', 'alphanohtml');
|
|
|
|
if (empty($token)) {
|
|
dol_syslog("IDS Connect Callback: Kein Token - POST-Daten: ".json_encode(array_keys($_POST)), LOG_WARNING);
|
|
http_response_code(400);
|
|
die("Missing token - Callback v".IDSCONNECT_CALLBACK_VERSION);
|
|
}
|
|
|
|
// Token verifizieren
|
|
$idsconnect = new IdsConnect($db);
|
|
$log = $idsconnect->verifyCallbackToken($token);
|
|
|
|
if ($log === false) {
|
|
dol_syslog("IDS Connect Callback: Ungültiger oder abgelaufener Token: ".$token." von IP: ".getUserRemoteIP(), LOG_WARNING);
|
|
http_response_code(403);
|
|
die("Invalid or expired token - Callback v".IDSCONNECT_CALLBACK_VERSION);
|
|
}
|
|
|
|
dol_syslog("IDS Connect Callback: Token gültig - LogID=".$log->id." Supplier=".$log->fk_supplier." Action=".$log->action_type, LOG_INFO);
|
|
|
|
// ============================================================
|
|
// Warenkorb-XML aus verschiedenen Quellen lesen
|
|
// ============================================================
|
|
$cart_xml = '';
|
|
$cart_source = '';
|
|
|
|
// 1. Reguläres POST-Feld 'warenkorb' (IDS Connect Standard)
|
|
if (!empty($_POST['warenkorb'])) {
|
|
$cart_xml = $_POST['warenkorb'];
|
|
$cart_source = 'POST[warenkorb]';
|
|
}
|
|
// 2. POST-Feld 'cart' (alternativer Name)
|
|
elseif (!empty($_POST['cart'])) {
|
|
$cart_xml = $_POST['cart'];
|
|
$cart_source = 'POST[cart]';
|
|
}
|
|
// 3. Datei-Upload 'warenkorb' (bei multipart/form-data möglich)
|
|
elseif (!empty($_FILES['warenkorb']['tmp_name']) && is_uploaded_file($_FILES['warenkorb']['tmp_name'])) {
|
|
$cart_xml = file_get_contents($_FILES['warenkorb']['tmp_name']);
|
|
$cart_source = 'FILES[warenkorb] ('.$_FILES['warenkorb']['name'].' '.$_FILES['warenkorb']['size'].' bytes)';
|
|
}
|
|
// 4. Datei-Upload 'cart'
|
|
elseif (!empty($_FILES['cart']['tmp_name']) && is_uploaded_file($_FILES['cart']['tmp_name'])) {
|
|
$cart_xml = file_get_contents($_FILES['cart']['tmp_name']);
|
|
$cart_source = 'FILES[cart] ('.$_FILES['cart']['name'].' '.$_FILES['cart']['size'].' bytes)';
|
|
}
|
|
// 5. Erster verfügbarer Datei-Upload
|
|
elseif (!empty($_FILES)) {
|
|
$first_file = reset($_FILES);
|
|
$first_key = key($_FILES);
|
|
if (!empty($first_file['tmp_name']) && is_uploaded_file($first_file['tmp_name'])) {
|
|
$cart_xml = file_get_contents($first_file['tmp_name']);
|
|
$cart_source = 'FILES['.$first_key.'] ('.$first_file['name'].' '.$first_file['size'].' bytes)';
|
|
}
|
|
}
|
|
// 6. Erster POST-Wert der XML enthält
|
|
if (empty($cart_xml)) {
|
|
foreach ($_POST as $key => $value) {
|
|
if (is_string($value) && (strpos($value, '<?xml') !== false || strpos($value, '<Warenkorb') !== false || strpos($value, '<Order') !== false)) {
|
|
$cart_xml = $value;
|
|
$cart_source = 'POST['.$key.'] (XML-Suche)';
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
// 7. Raw POST body als Fallback
|
|
if (empty($cart_xml)) {
|
|
$raw = file_get_contents('php://input');
|
|
if (!empty($raw)) {
|
|
if (strpos($raw, '<?xml') !== false || strpos($raw, '<Warenkorb') !== false) {
|
|
$cart_xml = $raw;
|
|
$cart_source = 'php://input ('.strlen($raw).' bytes)';
|
|
}
|
|
}
|
|
}
|
|
|
|
$callback_meta['cart_source'] = $cart_source;
|
|
|
|
dol_syslog("IDS Connect Callback: Cart-Source=".$cart_source." Cart-Länge=".strlen($cart_xml)." POST-Felder=".implode(',', array_keys($_POST))." FILES-Felder=".implode(',', array_keys($_FILES)), LOG_INFO);
|
|
|
|
// ============================================================
|
|
// Debug-Daten IMMER in DB speichern (egal was passiert)
|
|
// ============================================================
|
|
$debug_data = array(
|
|
'callback_version' => IDSCONNECT_CALLBACK_VERSION,
|
|
'callback_meta' => $callback_meta,
|
|
'cart_source' => $cart_source,
|
|
'cart_xml_length' => strlen($cart_xml),
|
|
'post_keys' => array_keys($_POST),
|
|
'post_values_preview' => array(),
|
|
'files_info' => array(),
|
|
);
|
|
// POST-Werte gekürzt speichern
|
|
foreach ($_POST as $k => $v) {
|
|
if ($k === 'pw_kunde') {
|
|
$debug_data['post_values_preview'][$k] = '***';
|
|
} elseif (is_string($v)) {
|
|
$debug_data['post_values_preview'][$k] = substr($v, 0, 500).(strlen($v) > 500 ? '...['.strlen($v).' bytes]' : '');
|
|
} else {
|
|
$debug_data['post_values_preview'][$k] = gettype($v);
|
|
}
|
|
}
|
|
// FILES-Info speichern
|
|
foreach ($_FILES as $k => $f) {
|
|
$debug_data['files_info'][$k] = array(
|
|
'name' => $f['name'] ?? '',
|
|
'type' => $f['type'] ?? '',
|
|
'size' => $f['size'] ?? 0,
|
|
'error' => $f['error'] ?? -1,
|
|
);
|
|
}
|
|
|
|
// Roh-XML immer speichern wenn vorhanden
|
|
if (!empty($cart_xml)) {
|
|
$log->updateCart($cart_xml);
|
|
}
|
|
|
|
// ============================================================
|
|
// OCI-Format prüfen (NEW_ITEM-* POST-Felder)
|
|
// ============================================================
|
|
$oci_items = array();
|
|
$has_oci = false;
|
|
foreach ($_POST as $key => $value) {
|
|
if (strpos($key, 'NEW_ITEM-') === 0) {
|
|
$has_oci = true;
|
|
break;
|
|
}
|
|
}
|
|
if ($has_oci) {
|
|
dol_syslog("IDS Connect Callback: OCI-Format erkannt (NEW_ITEM-* Felder)", LOG_INFO);
|
|
$cart_source = 'OCI (POST NEW_ITEM-* Felder)';
|
|
$callback_meta['cart_source'] = $cart_source;
|
|
$debug_data['cart_source'] = $cart_source;
|
|
$debug_data['format'] = 'OCI';
|
|
|
|
// OCI-Felder parsen: NEW_ITEM-FELDNAME[index] = wert
|
|
$oci_raw = array();
|
|
foreach ($_POST as $key => $value) {
|
|
if (preg_match('/^NEW_ITEM-([A-Z_]+)\[?(\d*)\]?$/', $key, $m)) {
|
|
$field = $m[1];
|
|
$idx = $m[2] !== '' ? (int) $m[2] : 1;
|
|
$oci_raw[$idx][$field] = $value;
|
|
}
|
|
// Alternatives Format: NEW_ITEM-FELDNAME ohne Index
|
|
elseif (preg_match('/^NEW_ITEM-([A-Z_]+)$/', $key, $m) && is_array($value)) {
|
|
foreach ($value as $idx => $val) {
|
|
$oci_raw[$idx][$m[1]] = $val;
|
|
}
|
|
}
|
|
}
|
|
|
|
foreach ($oci_raw as $idx => $fields) {
|
|
$item = array(
|
|
'artikelnr' => $fields['VENDORMAT'] ?? $fields['MATNR'] ?? $fields['EXT_PRODUCT_ID'] ?? '',
|
|
'bezeichnung' => $fields['DESCRIPTION'] ?? $fields['LONGTEXT'] ?? '',
|
|
'langtext' => $fields['LONGTEXT'] ?? '',
|
|
'menge' => (float) ($fields['QUANTITY'] ?? 0),
|
|
'einheit' => $fields['UNIT'] ?? 'STK',
|
|
'einzelpreis' => (float) ($fields['PRICE'] ?? 0),
|
|
'angebotspreis' => 0,
|
|
'gesamtpreis' => 0,
|
|
'ean' => $fields['EAN'] ?? '',
|
|
'hersteller' => $fields['MANUFACTMAT'] ?? $fields['VENDOR'] ?? '',
|
|
'herstellernr' => $fields['MANUFACTMAT'] ?? '',
|
|
'hinweis' => '',
|
|
);
|
|
if ($item['menge'] > 0 && $item['einzelpreis'] > 0) {
|
|
$item['gesamtpreis'] = $item['menge'] * $item['einzelpreis'];
|
|
}
|
|
if (!empty($item['artikelnr']) || !empty($item['bezeichnung'])) {
|
|
$oci_items[] = $item;
|
|
}
|
|
}
|
|
}
|
|
|
|
// ============================================================
|
|
// Verarbeitung
|
|
// ============================================================
|
|
|
|
// OCI-Artikel haben Vorrang wenn gefunden
|
|
if (!empty($oci_items)) {
|
|
$items = $oci_items;
|
|
// Als "XML" für die DB speichern (OCI-Rohdaten als JSON)
|
|
$oci_log = json_encode($_POST, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
|
|
$log->updateCart($oci_log);
|
|
$debug_data['result'] = 'success';
|
|
$debug_data['format'] = 'OCI';
|
|
$debug_data['item_count'] = count($items);
|
|
$debug_data['items'] = $items;
|
|
$log->updateStatus('success', json_encode($debug_data));
|
|
dol_syslog("IDS Connect Callback: OCI ".count($items)." Artikel empfangen für Supplier ".$log->fk_supplier, LOG_INFO);
|
|
|
|
$_SESSION['idsconnect_callback'] = array(
|
|
'log_id' => $log->id,
|
|
'supplier_id' => $log->fk_supplier,
|
|
'items' => $items,
|
|
'timestamp' => dol_now(),
|
|
);
|
|
|
|
idsconnectCallbackPage('Warenkorb empfangen (OCI): '.count($items).' Artikel', 'success', $log, $debug_data);
|
|
exit;
|
|
}
|
|
|
|
if (empty($cart_xml)) {
|
|
$debug_data['result'] = 'no_cart';
|
|
$log->updateStatus('cancelled', json_encode($debug_data), 'Kein Warenkorb empfangen');
|
|
dol_syslog("IDS Connect Callback: Kein Warenkorb empfangen für Token ".$token, LOG_INFO);
|
|
|
|
// Ergebnis direkt anzeigen (NOLOGIN-Seite, kein Redirect nötig)
|
|
idsconnectCallbackPage('Kein Warenkorb', 'warning', $log, $debug_data);
|
|
exit;
|
|
}
|
|
|
|
// Warenkorb parsen (IDS XML-Format)
|
|
$items = $idsconnect->parseCartXml($cart_xml);
|
|
|
|
if ($items === false) {
|
|
$debug_data['result'] = 'parse_error';
|
|
$debug_data['parse_error'] = $idsconnect->error;
|
|
$debug_data['cart_xml_preview'] = substr($cart_xml, 0, 3000);
|
|
$log->updateStatus('error', json_encode($debug_data), 'XML-Parse-Fehler: '.$idsconnect->error);
|
|
dol_syslog("IDS Connect Callback: XML-Parse-Fehler: ".$idsconnect->error." Quelle=".$cart_source." XML-Anfang: ".substr($cart_xml, 0, 300), LOG_ERR);
|
|
|
|
idsconnectCallbackPage('XML-Fehler: '.$idsconnect->error, 'error', $log, $debug_data, $cart_xml);
|
|
exit;
|
|
}
|
|
|
|
// Erfolg!
|
|
$debug_data['result'] = 'success';
|
|
$debug_data['item_count'] = count($items);
|
|
$debug_data['items'] = $items;
|
|
$log->updateStatus('success', json_encode($debug_data));
|
|
|
|
dol_syslog("IDS Connect Callback: ".count($items)." Artikel empfangen für Supplier ".$log->fk_supplier." XML-Länge=".strlen($cart_xml), LOG_INFO);
|
|
|
|
// Session-Daten für die Weiterverarbeitung
|
|
$_SESSION['idsconnect_callback'] = array(
|
|
'log_id' => $log->id,
|
|
'supplier_id' => $log->fk_supplier,
|
|
'items' => $items,
|
|
'timestamp' => dol_now(),
|
|
);
|
|
|
|
idsconnectCallbackPage('Warenkorb empfangen: '.count($items).' Artikel', 'success', $log, $debug_data);
|
|
exit;
|
|
|
|
|
|
// ============================================================
|
|
// HTML-Ausgabe-Funktion (kein Redirect, NOLOGIN-Seite)
|
|
// ============================================================
|
|
|
|
/**
|
|
* Zeigt das Callback-Ergebnis direkt an
|
|
*
|
|
* @param string $message Nachricht
|
|
* @param string $type success, error, warning
|
|
* @param IdsLog $log Log-Eintrag
|
|
* @param array $debug Debug-Daten
|
|
* @param string $raw_xml Roh-XML für Anzeige
|
|
*/
|
|
function idsconnectCallbackPage($message, $type, $log, $debug = array(), $raw_xml = '')
|
|
{
|
|
$colors = array(
|
|
'success' => array('bg' => '#d4edda', 'border' => '#28a745', 'text' => '#155724'),
|
|
'error' => array('bg' => '#f8d7da', 'border' => '#dc3545', 'text' => '#721c24'),
|
|
'warning' => array('bg' => '#fff3cd', 'border' => '#ffc107', 'text' => '#856404'),
|
|
);
|
|
$c = $colors[$type] ?? $colors['warning'];
|
|
|
|
// Dolibarr-Link: Die URL verwenden über die der User beim Launch eingeloggt war
|
|
// Priorität: 1. user_base_url aus Log, 2. IDSCONNECT_PUBLIC_URL, 3. $dolibarr_main_url_root
|
|
global $dolibarr_main_url_root;
|
|
$internal_base = '';
|
|
// Aus dem Log-Eintrag die Herkunfts-URL des Users lesen
|
|
if ($log && !empty($log->request_data)) {
|
|
$req = json_decode($log->request_data, true);
|
|
if (!empty($req['user_base_url'])) {
|
|
$internal_base = rtrim($req['user_base_url'], '/');
|
|
}
|
|
}
|
|
// Fallback auf IDSCONNECT_PUBLIC_URL oder $dolibarr_main_url_root
|
|
if (empty($internal_base)) {
|
|
$public_url = getDolGlobalString('IDSCONNECT_PUBLIC_URL');
|
|
if (!empty($public_url)) {
|
|
$internal_base = rtrim($public_url, '/');
|
|
} else {
|
|
$internal_base = $dolibarr_main_url_root;
|
|
if (!empty($internal_base) && strpos($internal_base, '://') === false) {
|
|
$internal_base = 'http://'.$internal_base;
|
|
}
|
|
}
|
|
}
|
|
$dolibarr_link = $internal_base.'/custom/idsconnect/idsconnectindex.php';
|
|
|
|
header('Content-Type: text/html; charset=UTF-8');
|
|
echo '<!DOCTYPE html><html><head><meta charset="UTF-8">';
|
|
echo '<title>IDS Connect Callback v'.IDSCONNECT_CALLBACK_VERSION.'</title>';
|
|
echo '<style>body{font-family:Arial,sans-serif;max-width:800px;margin:20px auto;padding:0 20px;background:#f5f5f5}';
|
|
echo '.box{padding:15px;border-radius:5px;margin:10px 0;border-left:4px solid}';
|
|
echo 'pre{background:#f8f9fa;padding:10px;overflow:auto;max-height:400px;font-size:12px;border:1px solid #ddd;border-radius:3px}';
|
|
echo 'details{margin:10px 0}summary{cursor:pointer;font-weight:bold;padding:5px}</style>';
|
|
echo '</head><body>';
|
|
|
|
echo '<h2>IDS Connect Callback <small style="color:#999">v'.IDSCONNECT_CALLBACK_VERSION.'</small></h2>';
|
|
|
|
// Hauptnachricht
|
|
echo '<div class="box" style="background:'.$c['bg'].';border-color:'.$c['border'].';color:'.$c['text'].'">';
|
|
echo '<strong>'.htmlspecialchars($message).'</strong>';
|
|
echo '<br>Log-Eintrag: #'.$log->id;
|
|
echo '</div>';
|
|
|
|
// Bei Erfolg: Artikelübersicht
|
|
if ($type === 'success' && !empty($debug['items'])) {
|
|
echo '<h3>Empfangene Artikel</h3>';
|
|
echo '<table style="width:100%;border-collapse:collapse;background:white">';
|
|
echo '<tr style="background:#2c3e50;color:white"><th style="padding:8px">Art.-Nr.</th><th style="padding:8px">Bezeichnung</th><th style="padding:8px;text-align:right">Menge</th><th style="padding:8px">Einheit</th><th style="padding:8px;text-align:right">Preis</th></tr>';
|
|
foreach ($debug['items'] as $item) {
|
|
echo '<tr style="border-bottom:1px solid #eee">';
|
|
echo '<td style="padding:6px"><code>'.htmlspecialchars($item['artikelnr'] ?? '').'</code></td>';
|
|
echo '<td style="padding:6px">'.htmlspecialchars($item['bezeichnung'] ?? '').'</td>';
|
|
echo '<td style="padding:6px;text-align:right">'.($item['menge'] ?? 0).'</td>';
|
|
echo '<td style="padding:6px">'.htmlspecialchars($item['einheit'] ?? 'STK').'</td>';
|
|
echo '<td style="padding:6px;text-align:right">'.number_format($item['einzelpreis'] ?? 0, 2, ',', '.').'</td>';
|
|
echo '</tr>';
|
|
}
|
|
echo '</table>';
|
|
}
|
|
|
|
// Debug-Infos
|
|
echo '<details><summary>Debug-Informationen</summary>';
|
|
echo '<table style="width:100%;background:white;border-collapse:collapse">';
|
|
|
|
$show_fields = array(
|
|
'Callback-Version' => $debug['callback_version'] ?? '-',
|
|
'Ergebnis' => $debug['result'] ?? '-',
|
|
'Cart-Quelle' => $debug['cart_source'] ?? 'keine',
|
|
'Cart-XML-Länge' => ($debug['cart_xml_length'] ?? 0).' Bytes',
|
|
'POST-Felder' => implode(', ', $debug['post_keys'] ?? array()) ?: 'keine',
|
|
'FILES-Felder' => implode(', ', array_keys($debug['files_info'] ?? array())) ?: 'keine',
|
|
'Content-Type' => $debug['callback_meta']['content_type'] ?? '-',
|
|
'IP-Adresse' => $debug['callback_meta']['remote_ip'] ?? '-',
|
|
'Zeitstempel' => $debug['callback_meta']['timestamp'] ?? '-',
|
|
);
|
|
|
|
foreach ($show_fields as $label => $value) {
|
|
echo '<tr style="border-bottom:1px solid #eee"><td style="padding:5px;font-weight:bold">'.htmlspecialchars($label).'</td>';
|
|
echo '<td style="padding:5px"><code>'.htmlspecialchars($value).'</code></td></tr>';
|
|
}
|
|
echo '</table>';
|
|
|
|
// POST-Werte
|
|
if (!empty($debug['post_values_preview'])) {
|
|
echo '<details><summary>POST-Werte (gekürzt)</summary><pre>';
|
|
echo htmlspecialchars(json_encode($debug['post_values_preview'], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
|
echo '</pre></details>';
|
|
}
|
|
|
|
// FILES-Info
|
|
if (!empty($debug['files_info'])) {
|
|
echo '<details><summary>FILES-Info</summary><pre>';
|
|
echo htmlspecialchars(json_encode($debug['files_info'], JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE));
|
|
echo '</pre></details>';
|
|
}
|
|
|
|
echo '</details>';
|
|
|
|
// Roh-XML bei Fehler anzeigen
|
|
if (!empty($raw_xml)) {
|
|
echo '<details><summary>Roh-XML ('.strlen($raw_xml).' Bytes)</summary>';
|
|
echo '<pre>'.htmlspecialchars(substr($raw_xml, 0, 5000)).'</pre>';
|
|
if (strlen($raw_xml) > 5000) {
|
|
echo '<p style="color:#999">... gekürzt, vollständiges XML im Log #'.$log->id.'</p>';
|
|
}
|
|
echo '</details>';
|
|
}
|
|
|
|
// Links
|
|
echo '<div style="margin-top:20px;padding:15px;background:white;border-radius:5px">';
|
|
echo '<p><strong>Weiter:</strong></p>';
|
|
echo '<a href="'.htmlspecialchars($dolibarr_link).'" style="display:inline-block;padding:8px 20px;background:#27ae60;color:white;text-decoration:none;border-radius:5px;margin-right:10px">Zur IDS Connect Übersicht</a>';
|
|
if ($type === 'success') {
|
|
$review_link = $internal_base.'/custom/idsconnect/cart_review.php?log_id='.$log->id;
|
|
echo '<a href="'.htmlspecialchars($review_link).'" style="display:inline-block;padding:8px 20px;background:#3498db;color:white;text-decoration:none;border-radius:5px">Warenkorb prüfen</a>';
|
|
}
|
|
echo '</div>';
|
|
|
|
echo '</body></html>';
|
|
}
|