Files
erp_naurua/modules/shared/auth/ui/home.php
T
2026-09-06 17:46:38 +02:00

1444 lines
130 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
declare(strict_types=1);
require_once __DIR__ . '/../service.php';
function auth_current_path(): string
{
$requestUri = (string) ($_SERVER['REQUEST_URI'] ?? '/');
$path = parse_url($requestUri, PHP_URL_PATH);
if (!is_string($path) || $path === '') {
return '/';
}
return $path;
}
function auth_build_path_with_query(array $query = []): string
{
$query = array_filter(
$query,
static fn ($value): bool => $value !== null && $value !== ''
);
$path = auth_current_path();
$queryString = http_build_query($query, '', '&', PHP_QUERY_RFC3986);
return $queryString === '' ? $path : $path . '?' . $queryString;
}
function auth_format_bestellung_date(?string $value): string
{
if ($value === null || $value === '') {
return '';
}
try {
return (new DateTimeImmutable($value))->format('d.m.Y H:i');
} catch (Throwable) {
return $value;
}
}
function auth_format_bestellung_total(?float $value): string
{
if ($value === null) {
return '';
}
return 'CHF ' . number_format($value, 2, '.', '\'');
}
function auth_render_bestellungen_large_table(array $bestellungenTable): string
{
$rows = $bestellungenTable['rows'] ?? [];
$search = (string) ($bestellungenTable['search'] ?? '');
$sortColumn = (string) ($bestellungenTable['sort_column'] ?? 'order_date');
$sortDirection = strtoupper((string) ($bestellungenTable['sort_direction'] ?? 'DESC'));
$limit = (int) ($bestellungenTable['limit'] ?? 20);
$pageSize = (int) ($bestellungenTable['page_size'] ?? 20);
$hasMore = (bool) ($bestellungenTable['has_more'] ?? false);
$nextLimit = (int) ($bestellungenTable['next_limit'] ?? $limit);
$sortColumns = [
'order_date' => 'Bestelldatum',
'external_ref' => 'Bestellnummer',
'name' => 'Name',
'total_amount' => 'Gesamtsumme',
];
$html = [];
$html[] = '<section class="sg-card-list-page" aria-label="Bestellungen">';
$html[] = '<article class="sg-card sg-large-table sg-large-table--bestellungen" style="margin-top: var(--spacing-large);" data-component="large-table" data-bestellungen-large-table="true" data-bestellungen-search="' . auth_escape_html($search) . '" data-bestellungen-sort-column="' . auth_escape_html($sortColumn) . '" data-bestellungen-sort-direction="' . auth_escape_html($sortDirection) . '" data-bestellungen-limit="' . $limit . '" data-bestellungen-page-size="' . $pageSize . '" role="table" aria-label="Bestellungen">';
$html[] = '<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-large-table__title-segment" data-component-part="large-table-header">';
$html[] = '<div class="sg-strong">Bestellungen</div>';
$html[] = '<span class="sg-search-field-row" data-component="search-field">';
$html[] = '<span class="sg-input-single-line-wrap" data-has-value="' . ($search !== '' ? 'true' : 'false') . '" data-component="single-line-input" data-component-state="' . ($search !== '' ? 'active' : 'inactive-selectable') . '">';
$html[] = '<input class="sg-interaction-element sg-input-single-line sg-search-field-input sg-input-single-line--inactive-selectable sg-form-inactive-selectable" type="text" placeholder="Suche" aria-label="Bestellungen durchsuchen" value="' . auth_escape_html($search) . '" data-large-table-search data-bestellungen-search-input>';
$html[] = '<button class="sg-input-clear-button" type="button" aria-label="Eingabe löschen" data-bestellungen-search-clear>×</button>';
$html[] = '</span>';
$html[] = '</span>';
$html[] = '</div>';
$html[] = '<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row sg-large-table__row--header" role="row" data-component-part="large-table-header-row">';
$headerIndex = 0;
foreach ($sortColumns as $column => $label) {
$isActive = $column === $sortColumn;
$headerDirection = $isActive ? strtolower($sortDirection) : 'none';
$iconDirection = $isActive ? strtolower($sortDirection) : 'ascending';
$ariaLabel = $isActive
? $label . ' ' . ($sortDirection === 'ASC' ? 'aufsteigend sortiert' : 'absteigend sortiert')
: $label . ' sortieren';
$targetDirection = $isActive
? ($sortDirection === 'ASC' ? 'DESC' : 'ASC')
: ($column === 'order_date' ? 'DESC' : 'ASC');
$amountHeaderClass = $column === 'total_amount' ? ' sg-large-table__cell--amount' : '';
$html[] = '<div class="sg-large-table__cell sg-large-table__cell--header' . $amountHeaderClass . '" role="columnheader" aria-sort="' . $headerDirection . '" data-sort-key="' . $headerIndex . '">';
$html[] = '<button class="sg-large-table__sort-button" type="button" aria-label="' . auth_escape_html($ariaLabel) . '" data-bestellungen-sort-button="true" data-bestellungen-sort-column="' . auth_escape_html($column) . '" data-bestellungen-sort-direction="' . auth_escape_html($targetDirection) . '">';
$html[] = '<span class="sg-large-table__sort-label">' . auth_escape_html($label) . '</span>';
$html[] = '<span class="sg-large-table__sort-icon" aria-hidden="true" data-direction="' . auth_escape_html($iconDirection) . '"></span>';
$html[] = '</button>';
$html[] = '</div>';
$headerIndex++;
}
$html[] = '</div>';
foreach ($rows as $index => $row) {
$isStriped = $index % 2 === 1;
$rowClass = 'sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row';
if ($isStriped) {
$rowClass .= ' sg-large-table__row--striped-light';
}
$orderNumber = (string) ($row['external_ref'] ?? '');
$orderDate = auth_format_bestellung_date((string) ($row['order_date'] ?? ''));
$totalAmount = auth_format_bestellung_total(isset($row['total_amount']) ? (float) $row['total_amount'] : null);
$firstName = (string) ($row['first_name'] ?? '');
$lastName = (string) ($row['last_name'] ?? '');
$name = trim($firstName . ' ' . $lastName);
$street = (string) ($row['street'] ?? '');
$houseNumber = (string) ($row['house_number'] ?? '');
$zip = (string) ($row['zip'] ?? '');
$city = (string) ($row['city'] ?? '');
$country = (string) ($row['country_name'] ?? '');
$html[] = '<div class="' . $rowClass . '" role="row" data-component-part="large-table-row" data-bestellungen-row="true" data-order-id="' . (int) ($row['id'] ?? 0) . '">';
$html[] = '<div class="sg-large-table__cell" role="cell">' . auth_escape_html($orderDate) . '</div>';
$html[] = '<div class="sg-large-table__cell" role="cell">';
$html[] = '<a class="sg-hyperlink" href="#" aria-haspopup="dialog" aria-expanded="false" data-order-drawer-open="true" data-order-id="' . (int) ($row['id'] ?? 0) . '" data-order-number="' . auth_escape_html($orderNumber) . '" data-order-date="' . auth_escape_html($orderDate) . '" data-order-total="' . auth_escape_html($totalAmount) . '" data-order-first-name="' . auth_escape_html($firstName) . '" data-order-last-name="' . auth_escape_html($lastName) . '" data-order-street="' . auth_escape_html($street) . '" data-order-house-number="' . auth_escape_html($houseNumber) . '" data-order-zip="' . auth_escape_html($zip) . '" data-order-city="' . auth_escape_html($city) . '" data-order-country="' . auth_escape_html($country) . '">' . auth_escape_html($orderNumber) . '</a>';
$html[] = '</div>';
$html[] = '<div class="sg-large-table__cell" role="cell">';
$html[] = '<a class="sg-hyperlink" href="#" aria-haspopup="dialog" aria-expanded="false" data-order-drawer-open="true" data-order-id="' . (int) ($row['id'] ?? 0) . '" data-order-number="' . auth_escape_html($orderNumber) . '" data-order-date="' . auth_escape_html($orderDate) . '" data-order-total="' . auth_escape_html($totalAmount) . '" data-order-first-name="' . auth_escape_html($firstName) . '" data-order-last-name="' . auth_escape_html($lastName) . '" data-order-street="' . auth_escape_html($street) . '" data-order-house-number="' . auth_escape_html($houseNumber) . '" data-order-zip="' . auth_escape_html($zip) . '" data-order-city="' . auth_escape_html($city) . '" data-order-country="' . auth_escape_html($country) . '">' . auth_escape_html($name) . '</a>';
$html[] = '</div>';
$html[] = '<div class="sg-large-table__cell sg-large-table__cell--amount" role="cell">' . auth_escape_html($totalAmount) . '</div>';
$html[] = '</div>';
}
if ($hasMore) {
$loadMoreUrl = auth_build_path_with_query([
'bestellungen_search' => $search !== '' ? $search : null,
'bestellungen_sort' => $sortColumn,
'bestellungen_dir' => $sortDirection,
'bestellungen_limit' => $nextLimit,
]);
$html[] = '<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row sg-large-table__row--load-more" role="row" data-component-part="large-table-row" data-large-table-load-more-row="true">';
$html[] = '<div class="sg-large-table__cell sg-large-table__cell--load-more" role="cell">';
$html[] = '<div class="sg-navigation-card-layout sg-large-table__load-more-layout">';
$html[] = '<div class="sg-navigation-card-block">';
$html[] = '<article class="sg-card" data-component="card" data-pattern="navigation-card" aria-label="Mehr laden">';
$html[] = '<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body" data-pattern-part="navigation-card-segment">';
$html[] = '<div class="sg-navigation-card-center">';
$html[] = '<a class="sg-hyperlink" href="' . auth_escape_html($loadMoreUrl) . '" data-component="hyperlink" data-large-table-load-more-trigger="true">Mehr laden</a>';
$html[] = '</div>';
$html[] = '</div>';
$html[] = '</article>';
$html[] = '</div>';
$html[] = '</div>';
$html[] = '</div>';
$html[] = '</div>';
}
$html[] = '</article>';
$html[] = '</section>';
$html[] = '<div class="sg-card-list-page-drawer-backdrop" aria-hidden="true" data-bestellungen-drawer-backdrop="true" data-open="false"></div>';
$html[] = '<aside class="sg-card-list-page-drawer" aria-label="Bestell-Details" aria-hidden="true" data-bestellungen-drawer="true" data-open="false">';
$html[] = '<div class="sg-card-list-page-drawer__header">';
$html[] = '<h2 class="sg-heading-h2 sg-card-list-page-drawer__title" data-order-drawer-title>Bestellung</h2>';
$html[] = '<button class="sg-interaction-element sg-hyperlink" type="button" data-order-drawer-close>schliessen</button>';
$html[] = '</div>';
$html[] = '<div class="sg-card-list-page-drawer__content" data-order-drawer-cards>';
$html[] = '<p class="sg-body" data-order-drawer-loading>Bestelldetails werden geladen …</p>';
$html[] = '</div>';
$html[] = '</aside>';
return implode('', $html);
}
function auth_render_bestellungen_content(array $bestellungenTable): string
{
return '<div data-bestellungen-content="true">'
. '<article class="sg-card" data-component="basic-card"><div class="sg-card-segment sg-card-segment--body sg-card-segment--gray" data-component-part="card-body"><div class="sg-component-row sg-basic-card__actions"><button class="sg-interaction-element sg-button sg-button--active" type="button" aria-haspopup="dialog" aria-expanded="false" data-component="button" data-component-state="active" data-otc-order-open>OTC-Bestellung erfassen</button></div></div></article>'
. auth_render_bestellungen_large_table($bestellungenTable)
. '</div>';
}
function auth_render_lager_table(string $title, array $rows, array $columns, string $tableKey): string
{
$html = [];
$html[] = '<article class="sg-card sg-large-table sg-large-table--lager" data-component="large-table" data-lager-table="true" data-lager-table-key="' . auth_escape_html($tableKey) . '" role="table" aria-label="' . auth_escape_html($title) . '">';
$html[] = '<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-large-table__title-segment" data-component-part="large-table-header"><div class="sg-strong">' . auth_escape_html($title) . '</div></div>';
$html[] = '<div class="sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row sg-large-table__row--header" role="row" data-component-part="large-table-header-row">';
foreach ($columns as $label) {
$html[] = '<div class="sg-large-table__cell sg-large-table__cell--header" role="columnheader"><span class="sg-large-table__sort-label">' . auth_escape_html($label) . '</span></div>';
}
$html[] = '</div>';
foreach ($rows as $index => $row) {
$rowClass = 'sg-card-segment sg-card-segment--body sg-card-segment--white sg-large-table__row';
if ($index % 2 === 1) {
$rowClass .= ' sg-large-table__row--striped-light';
}
$id = (int) ($row['id'] ?? 0);
$name = (string) ($row['name'] ?? $row['display_name'] ?? '');
$value = $tableKey === 'products'
? (string) max(0, (int) round((float) ($row['available_qty'] ?? 0)))
: (string) ($row['item_code'] ?? '');
$forecastText = '';
$forecastWarning = false;
$forecastMhdWarning = false;
if ($tableKey === 'products') {
$forecastStatus = (string) ($row['sellout_forecast_status'] ?? 'no_demand');
$forecastDate = $row['sellout_date'] ?? null;
if ($forecastDate !== null && $forecastDate !== '') {
$forecastDateObject = new DateTimeImmutable((string) $forecastDate);
$forecastText = $forecastDateObject->format('d.m.Y');
if ($forecastStatus === 'depleted') {
$forecastWarning = true;
$forecastText .= ' (CHARGE ENDE)';
} elseif (!empty($row['expiry_date'])) {
$expiryDate = new DateTimeImmutable((string) $row['expiry_date']);
$forecastWarning = $forecastDateObject >= $expiryDate->modify('-3 months')
&& $forecastDateObject <= $expiryDate;
$forecastMhdWarning = $forecastDateObject > $expiryDate;
if ($forecastWarning || $forecastMhdWarning) {
$forecastText .= ' (MHD: ' . $expiryDate->format('d.m.Y') . ')';
}
}
} else {
$forecastText = 'Keine Prognose';
}
}
$nameData = ' data-lager-drawer-name="' . auth_escape_html($name) . '"';
$valueData = ' data-lager-drawer-value="' . auth_escape_html($value) . '"';
$typeData = ' data-lager-drawer-type="' . auth_escape_html($tableKey === 'products' ? 'Produkt' : 'Artikel') . '"';
$detailData = '';
if ($tableKey === 'products') {
$detailData = ' data-lager-drawer-forecast="' . auth_escape_html($forecastText) . '"'
. ' data-lager-drawer-forecast-status="' . auth_escape_html($forecastStatus) . '"'
. ' data-lager-drawer-forecast-warning="' . ($forecastWarning ? 'true' : 'false') . '"'
. ' data-lager-drawer-forecast-mhd-warning="' . ($forecastMhdWarning ? 'true' : 'false') . '"'
. ' data-lager-drawer-current-qty="' . auth_escape_html(auth_format_lager_quantity((float) ($row['available_qty'] ?? 0))) . '"'
. ' data-lager-drawer-qty-in="' . auth_escape_html(auth_format_lager_quantity((float) ($row['qty_in'] ?? 0))) . '"'
. ' data-lager-drawer-virtual-shortage-qty="' . auth_escape_html(auth_format_lager_quantity((float) ($row['virtual_shortage_qty'] ?? 0))) . '"'
. ' data-lager-drawer-lot-id="' . auth_escape_html((string) ($row['lot_id'] ?? '')) . '"'
. ' data-lager-drawer-lot-number="' . auth_escape_html((string) ($row['lot_number'] ?? '')) . '"'
. ' data-lager-drawer-manufacturer-party-id="' . auth_escape_html((string) ($row['manufacturer_party_id'] ?? '')) . '"'
. ' data-lager-drawer-manufacturer-name="' . auth_escape_html((string) ($row['manufacturer_name'] ?? '')) . '"'
. ' data-lager-drawer-manufacturer-lot-number="' . auth_escape_html((string) ($row['manufacturer_lot_number'] ?? '')) . '"'
. ' data-lager-drawer-mfg-date="' . auth_escape_html((string) ($row['mfg_date'] ?? '')) . '"'
. ' data-lager-drawer-expiry-date="' . auth_escape_html((string) ($row['expiry_date'] ?? '')) . '"'
. ' data-lager-drawer-purchase-date="' . auth_escape_html((string) ($row['purchase_date'] ?? '')) . '"'
. ' data-lager-drawer-virtual-lot-number="' . auth_escape_html((string) ($row['virtual_lot_number'] ?? '')) . '"';
$openLot = $row['open_lots'][0] ?? [];
$detailData .= ' data-lager-open-lot-id="' . auth_escape_html((string) ($openLot['lot_id'] ?? '')) . '"'
. ' data-lager-open-lot-number="' . auth_escape_html((string) ($openLot['lot_number'] ?? '')) . '"'
. ' data-lager-open-manufacturer-party-id="' . auth_escape_html((string) ($openLot['manufacturer_party_id'] ?? '')) . '"'
. ' data-lager-open-manufacturer-lot-number="' . auth_escape_html((string) ($openLot['manufacturer_lot_number'] ?? '')) . '"'
. ' data-lager-open-mfg-date="' . auth_escape_html((string) ($openLot['mfg_date'] ?? '')) . '"'
. ' data-lager-open-expiry-date="' . auth_escape_html((string) ($openLot['expiry_date'] ?? '')) . '"'
. ' data-lager-open-purchase-date="' . auth_escape_html((string) ($openLot['purchase_date'] ?? '')) . '"';
}
$html[] = '<div class="' . $rowClass . '" role="row" data-component-part="large-table-row" data-lager-row="true" data-lager-id="' . $id . '">';
$html[] = '<div class="sg-large-table__cell" role="cell"><a class="sg-hyperlink" href="#" aria-haspopup="dialog" aria-expanded="false" data-lager-drawer-open="true"' . $nameData . $valueData . $typeData . $detailData . '>' . auth_escape_html($name) . '</a></div>';
$html[] = '<div class="sg-large-table__cell" role="cell"><a class="sg-hyperlink" href="#" aria-haspopup="dialog" aria-expanded="false" data-lager-drawer-open="true"' . $nameData . $valueData . $typeData . $detailData . '>' . auth_escape_html($value) . '</a></div>';
if ($tableKey === 'products') {
$forecastClass = $forecastWarning
? ' sg-strong lager-forecast-warning'
: ($forecastMhdWarning ? ' sg-strong lager-forecast-mhd-warning' : '');
$html[] = '<div class="sg-large-table__cell' . $forecastClass . '" role="cell">' . auth_escape_html($forecastText) . '</div>';
}
$html[] = '</div>';
}
$html[] = '</article>';
return implode('', $html);
}
function auth_format_lager_date(?string $value): string
{
if ($value === null || $value === '') {
return 'Nicht hinterlegt';
}
return (new DateTimeImmutable($value))->format(str_contains($value, ':') ? 'd.m.Y H:i' : 'd.m.Y');
}
function auth_format_lager_quantity(float $value): string
{
return fmod($value, 1.0) === 0.0
? number_format($value, 0, ',', '.')
: number_format($value, 2, ',', '.');
}
function auth_render_lager_historical_lots(array $lagerProducts): string
{
$html = [];
foreach ($lagerProducts as $product) {
$productId = (int) ($product['id'] ?? 0);
$html[] = '<div data-lager-historical-product="' . $productId . '" hidden>';
foreach (($product['historical_lots'] ?? []) as $lot) {
$qtyNet = (float) ($lot['qty_net'] ?? 0);
$emptyDate = $qtyNet <= 0 ? auth_format_lager_date($lot['last_out_at'] ?? null) : 'Nicht eindeutig';
$html[] = '<article class="sg-card sg-card--content-card" data-component="content-card" aria-label="Vergangene Charge">'
. '<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkgreen" data-component-part="card-header"><div class="sg-strong sg-text-on-dark">Vergangene Charge</div></div>'
. '<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body">'
. '<p class="sg-body"><strong>Naurua-Chargennummer:</strong> ' . auth_escape_html((string) ($lot['lot_number'] ?? 'Nicht hinterlegt')) . '<br>'
. '<strong>Status:</strong> Abgeschlossen<br>'
. '<strong>Eingangsmenge:</strong> ' . auth_format_lager_quantity((float) ($lot['qty_in'] ?? 0)) . '<br>'
. '<strong>Verbrauchte Menge:</strong> ' . auth_format_lager_quantity((float) ($lot['qty_out'] ?? 0)) . '<br>'
. '<strong>Verbrauchszeitraum:</strong> ' . auth_format_lager_date($lot['first_in_at'] ?? null) . ' – ' . auth_format_lager_date($lot['last_out_at'] ?? null) . '<br>'
. '<strong>Aufgebraucht am:</strong> ' . $emptyDate . '<br>'
. '<strong>MHD:</strong> ' . auth_format_lager_date($lot['expiry_date'] ?? null) . '<br>'
. '<strong>Hersteller:</strong> ' . auth_escape_html((string) ($lot['manufacturer_name'] ?? 'Nicht hinterlegt')) . '<br>'
. '<strong>Hersteller-Chargennummer:</strong> ' . auth_escape_html((string) ($lot['manufacturer_lot_number'] ?? 'Nicht hinterlegt')) . '</p>'
. '</div></article>';
}
$html[] = '</div>';
}
return implode('', $html);
}
function auth_render_lager_open_lots(array $lagerProducts, string $manufacturerOptions): string
{
$html = [];
foreach ($lagerProducts as $product) {
$productId = (int) ($product['id'] ?? 0);
$html[] = '<div data-lager-open-product="' . $productId . '" hidden>';
foreach (($product['open_lots'] ?? []) as $lot) {
$lotId = (int) ($lot['lot_id'] ?? 0);
$html[] = '<article class="sg-card sg-card--content-card" data-component="content-card" data-lager-open-card-wrapper="' . $lotId . '" aria-label="Offene Charge">'
. '<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkgreen sg-object-card__header" data-component-part="card-header"><div class="sg-strong sg-text-on-dark">Offene Charge</div><button class="sg-interaction-element sg-button sg-button--active" type="button" data-lager-open-edit-open>Bearbeiten</button></div>'
. '<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body" data-lager-open-card="' . (int) ($lot['lot_id'] ?? 0) . '"><p class="sg-body"><strong>Naurua-Chargennummer:</strong> <span data-lager-open-card-lot-number>' . auth_escape_html((string) ($lot['lot_number'] ?? 'Nicht hinterlegt')) . '</span><br>'
. '<strong>Status:</strong> Vorbereitet<br>'
. '<strong>Bestand:</strong> <span data-lager-open-card-qty-net>' . auth_format_lager_quantity((float) ($lot['qty_net'] ?? 0)) . '</span><br>'
. '<strong>Eingangsmenge:</strong> <span data-lager-open-card-qty-in>' . auth_format_lager_quantity((float) ($lot['qty_in'] ?? 0)) . '</span><br>'
. '<strong>Hersteller:</strong> <span data-lager-open-card-manufacturer>' . auth_escape_html((string) ($lot['manufacturer_name'] ?? 'Nicht hinterlegt')) . '</span><br>'
. '<strong>Hersteller-Chargennummer:</strong> <span data-lager-open-card-manufacturer-lot>' . auth_escape_html((string) ($lot['manufacturer_lot_number'] ?? 'Nicht hinterlegt')) . '</span><br>'
. '<strong>Herstellungsdatum:</strong> <span data-lager-open-card-mfg-date>' . auth_format_lager_date($lot['mfg_date'] ?? null) . '</span><br>'
. '<strong>MHD:</strong> <span data-lager-open-card-expiry-date>' . auth_format_lager_date($lot['expiry_date'] ?? null) . '</span><br>'
. '<strong>Einkaufsdatum:</strong> <span data-lager-open-card-purchase-date>' . auth_format_lager_date($lot['purchase_date'] ?? null) . '</span></p></div>'
. '<div class="sg-card-segment sg-card-segment--body sg-card-segment--gray" data-lager-open-edit-form hidden><div class="sg-form-sections-card-wrapper" data-pattern="form-sections" aria-label="Offene Charge bearbeiten"><form class="sg-form-sections-card" data-lager-open-edit-form-element><div class="sg-form-sections-card__body" data-pattern-part="form-body"><h2 class="sg-strong sg-form-sections-card__title">Offene Charge bearbeiten</h2>'
. '<section class="sg-form-sections-card__chapter" aria-labelledby="lager-open-charge-data-' . $lotId . '"><h2 id="lager-open-charge-data-' . $lotId . '" class="sg-strong sg-form-sections-card__chapter-title">Chargendaten</h2>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Naurua-Chargennummer</span><input class="sg-interaction-element sg-input-single-line" type="text" data-lager-open-lot-number required value="' . auth_escape_html((string) ($lot['lot_number'] ?? '')) . '"></label></div>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Hersteller</span><select class="sg-interaction-element sg-input-single-line" data-lager-open-manufacturer>' . str_replace('value="' . (int) ($lot['manufacturer_party_id'] ?? 0) . '"', 'value="' . (int) ($lot['manufacturer_party_id'] ?? 0) . '" selected', $manufacturerOptions) . '</select></label></div>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Hersteller-Chargennummer</span><input class="sg-interaction-element sg-input-single-line" type="text" data-lager-open-manufacturer-lot value="' . auth_escape_html((string) ($lot['manufacturer_lot_number'] ?? '')) . '"></label></div>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Herstellungsdatum</span><input class="sg-interaction-element sg-input-single-line" type="date" data-lager-open-mfg-date value="' . auth_escape_html((string) ($lot['mfg_date'] ?? '')) . '"></label></div>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">MHD</span><input class="sg-interaction-element sg-input-single-line" type="date" data-lager-open-expiry-date value="' . auth_escape_html((string) ($lot['expiry_date'] ?? '')) . '"></label></div>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Einkaufsdatum</span><input class="sg-interaction-element sg-input-single-line" type="date" data-lager-open-purchase-date value="' . auth_escape_html((string) ($lot['purchase_date'] ?? '')) . '"></label></div>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Zugang buchen</span><input class="sg-interaction-element sg-input-single-line" type="number" min="0" step="1" inputmode="numeric" data-lager-open-receipt-qty placeholder="Menge"></label></div>'
. '</section><footer class="sg-form-sections-card__actions-segment" data-pattern-part="form-actions-segment"><div class="sg-form-sections-card__actions" data-pattern-part="form-actions"><button class="sg-interaction-element sg-button sg-button--active sg-form-sections-card__action" type="button" data-lager-open-edit-close>Abbrechen</button><button class="sg-interaction-element sg-button sg-button--process sg-form-sections-card__action" type="submit">Speichern</button></div></footer><p class="sg-body" data-lager-open-edit-status aria-live="polite"></p></div></form></div></div></article>';
}
$html[] = '</div>';
}
return implode('', $html);
}
function auth_render_lager_content(array $lagerProducts, array $lagerArtikel, array $lagerManufacturers, string $csrfToken, string $sectionTitle = 'Lager'): string
{
$manufacturerOptions = '<option value="">Hersteller auswählen</option>';
foreach ($lagerManufacturers as $manufacturer) {
$manufacturerOptions .= '<option value="' . (int) ($manufacturer['id'] ?? 0) . '">' . auth_escape_html((string) ($manufacturer['name'] ?? '')) . '</option>';
}
$tables = $sectionTitle === 'Lager'
? auth_render_lager_table('Produkte', $lagerProducts, ['Produktname', 'Anzahl im Lager', 'Verbraucht bis'], 'products')
: auth_render_lager_table('Artikel', $lagerArtikel, ['Artikel-Name', 'Artikelnummer'], 'articles');
return '<div data-lager-content="true" data-lager-csrf-token="' . auth_escape_html($csrfToken) . '">'
. '<section class="sg-card-list-page" aria-label="' . auth_escape_html($sectionTitle) . '">'
. $tables
. '</section>'
. '<div class="sg-card-list-page-drawer-backdrop" aria-hidden="true" data-lager-drawer-backdrop="true" data-open="false"></div>'
. '<aside class="sg-card-list-page-drawer" aria-label="Lager-Details" aria-hidden="true" data-lager-drawer="true" data-open="false">'
. '<div class="sg-card-list-page-drawer__header"><h2 class="sg-heading-h2 sg-card-list-page-drawer__title" data-lager-drawer-title>Lager-Details</h2><button class="sg-interaction-element sg-hyperlink" type="button" data-lager-drawer-close>schliessen</button></div>'
. '<div class="sg-card-list-page-drawer__content">'
. '<article class="sg-card sg-vsf-drawer-card" data-component="card" data-pattern="card" aria-label="Lager-Details">'
. '<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-vsf-drawer-card__header"><div class="sg-strong">Lager-Details</div></header>'
. '<div class="sg-card-segment sg-card-segment--body sg-vsf-drawer-card__content"><p class="sg-body"><strong>Name:</strong> <span data-lager-drawer-name-value></span></p><p class="sg-body" data-lager-drawer-value-row><strong data-lager-drawer-value-label>Wert:</strong> <span data-lager-drawer-value-value></span></p></div>'
. '</article>'
. '<article class="sg-card sg-card--content-card" data-component="content-card" data-lager-drawer-topic="warning" aria-label="Warnungen">'
. '<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkgreen" data-component-part="card-header" data-lager-drawer-warning-header><div class="sg-strong sg-text-on-dark" data-lager-drawer-warning-title>Keine Warnung</div></div>'
. '<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body"><p class="sg-body" data-lager-drawer-warning-value></p></div>'
. '</article>'
. '<div class="sg-inline-controls-row" data-lager-drawer-topic="new-lot-action"><button class="sg-interaction-element sg-button sg-button--active" type="button" data-lager-new-lot-open>Neue Charge anlegen</button></div>'
. '<article class="sg-card sg-card--content-card" data-lager-drawer-topic="new-lot-form" aria-label="Neue Charge anlegen" hidden>'
. '<div class="sg-card-segment sg-card-segment--body sg-card-segment--gray"><div class="sg-form-sections-card-wrapper" data-pattern="form-sections" aria-label="Neue Charge anlegen"><form class="sg-form-sections-card" data-lager-new-lot-form-element><div class="sg-form-sections-card__body" data-pattern-part="form-body"><h2 class="sg-strong sg-form-sections-card__title">Neue Charge anlegen</h2>'
. '<div class="sg-notifications-pattern" data-lager-new-lot-notification-wrapper hidden><article class="sg-card sg-notifications-pattern__card" data-pattern="notification-small" data-component="notification-card"><div class="sg-card-segment sg-card-segment--header sg-card-segment--signal-green sg-notifications-pattern__text-segment sg-notifications-pattern__text-segment--small" data-component-part="card-header"><p class="sg-body" data-lager-new-lot-notification></p></div></article></div>'
. '<section class="sg-form-sections-card__chapter" aria-labelledby="lager-new-charge-data-title"><h2 id="lager-new-charge-data-title" class="sg-strong sg-form-sections-card__chapter-title">Chargendaten</h2>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Naurua-Chargennummer</span><input class="sg-interaction-element sg-input-single-line" type="text" data-lager-new-lot-number required></label></div>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Hersteller</span><select class="sg-interaction-element sg-input-single-line" data-lager-new-manufacturer>' . $manufacturerOptions . '</select></label></div>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Hersteller-Chargennummer</span><input class="sg-interaction-element sg-input-single-line" type="text" data-lager-new-manufacturer-lot></label></div>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Herstellungsdatum</span><input class="sg-interaction-element sg-input-single-line" type="date" data-lager-new-mfg-date></label></div>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">MHD</span><input class="sg-interaction-element sg-input-single-line" type="date" data-lager-new-expiry-date></label></div>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Einkaufsdatum</span><input class="sg-interaction-element sg-input-single-line" type="date" data-lager-new-purchase-date></label></div>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Eingangsmenge</span><input class="sg-interaction-element sg-input-single-line" type="number" min="0" step="1" inputmode="numeric" data-lager-new-receipt-qty placeholder="Menge"></label></div>'
. '</section><footer class="sg-form-sections-card__actions-segment" data-pattern-part="form-actions-segment"><div class="sg-form-sections-card__actions" data-pattern-part="form-actions"><button class="sg-interaction-element sg-button sg-button--active sg-form-sections-card__action" type="button" data-lager-new-lot-close>Abbrechen</button><button class="sg-interaction-element sg-button sg-button--process sg-form-sections-card__action" type="submit">Speichern</button></div></footer><p class="sg-body" data-lager-new-lot-status aria-live="polite"></p></div></form></div></div>'
. '</article>'
. '<div data-lager-drawer-topic="open-lots" aria-label="Offene Chargen">' . auth_render_lager_open_lots($lagerProducts, $manufacturerOptions) . '</div>'
. '<article class="sg-card sg-card--content-card" data-component="content-card" data-lager-drawer-topic="lot" aria-label="Aktive Charge">'
. '<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkgreen sg-object-card__header" data-component-part="card-header"><div class="sg-strong sg-text-on-dark">Aktive Charge</div><button class="sg-interaction-element sg-button sg-button--active" type="button" data-lager-edit-open>Bearbeiten</button></div>'
. '<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body" data-lager-read-view><p class="sg-body"><strong>Naurua-Chargennummer:</strong> <span data-lager-drawer-lot-number></span><br><strong>Aktueller Bestand:</strong> <span data-lager-drawer-current-qty></span><br><strong>Eingangsmenge:</strong> <span data-lager-drawer-qty-in></span><br><strong>Hersteller:</strong> <span data-lager-drawer-manufacturer-name></span><br><strong>Hersteller-Chargennummer:</strong> <span data-lager-drawer-manufacturer-lot-number></span><br><strong>Herstellungsdatum:</strong> <span data-lager-drawer-mfg-date></span><br><strong>MHD:</strong> <span data-lager-drawer-expiry-date></span><br><strong>Einkaufsdatum:</strong> <span data-lager-drawer-purchase-date></span></p></div>'
. '<div class="sg-card-segment sg-card-segment--body sg-card-segment--gray" data-lager-edit-form hidden><div class="sg-form-sections-card-wrapper" data-pattern="form-sections" aria-label="Aktive Charge bearbeiten">'
. '<form class="sg-form-sections-card" data-lager-edit-form-element><div class="sg-form-sections-card__body" data-pattern-part="form-body"><h2 class="sg-strong sg-form-sections-card__title">Aktive Charge bearbeiten</h2>'
. '<section class="sg-form-sections-card__chapter" aria-labelledby="lager-charge-traceability-title"><h2 id="lager-charge-traceability-title" class="sg-strong sg-form-sections-card__chapter-title">Rückverfolgbarkeit</h2>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Naurua-Chargennummer</span><input class="sg-interaction-element sg-input-single-line sg-form-inactive-selectable" type="text" data-lager-lot-number readonly></label></div>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Hersteller</span><select class="sg-interaction-element sg-input-single-line" id="lager-manufacturer" data-lager-manufacturer>' . $manufacturerOptions . '</select></label></div>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Hersteller-Chargennummer</span><input class="sg-interaction-element sg-input-single-line" type="text" id="lager-manufacturer-lot" data-lager-manufacturer-lot></label></div>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Herstellungsdatum</span><input class="sg-interaction-element sg-input-single-line" type="date" id="lager-mfg-date" data-lager-mfg-date></label></div>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">MHD</span><input class="sg-interaction-element sg-input-single-line" type="date" id="lager-expiry-date" data-lager-expiry-date></label></div>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Einkaufsdatum</span><input class="sg-interaction-element sg-input-single-line" type="date" id="lager-purchase-date" data-lager-purchase-date></label></div>'
. '</section><section class="sg-form-sections-card__chapter" aria-labelledby="lager-charge-movements-title"><h2 id="lager-charge-movements-title" class="sg-strong sg-form-sections-card__chapter-title">Lagerbewegungen</h2>'
. '<p class="sg-form-sections-card__sentence">Buchungen werden zusätzlich zur Rückverfolgbarkeit als Lagerbewegung gespeichert. Positive Werte erhöhen den Bestand, negative Werte reduzieren ihn.</p>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Zugang buchen</span><input class="sg-interaction-element sg-input-single-line" type="number" min="0" step="0.01" inputmode="decimal" data-lager-receipt-qty placeholder="Menge"></label></div>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Bestandskorrektur (+ / −)</span><input class="sg-interaction-element sg-input-single-line" type="number" step="1" inputmode="numeric" data-lager-adjustment-qty placeholder="+ / − Menge"></label></div>'
. '<div class="sg-form-sections-card__field-group"><label class="sg-labeled-input-row"><span class="sg-label">Abgang buchen</span><input class="sg-interaction-element sg-input-single-line" type="number" min="0" step="0.01" inputmode="decimal" data-lager-out-qty placeholder="Menge"></label></div>'
. '</section><footer class="sg-form-sections-card__actions-segment" data-pattern-part="form-actions-segment"><div class="sg-form-sections-card__actions" data-pattern-part="form-actions"><button class="sg-interaction-element sg-button sg-button--active sg-form-sections-card__action" type="button" data-lager-edit-close>Abbrechen</button><button class="sg-interaction-element sg-button sg-button--process sg-form-sections-card__action" type="submit">Speichern</button></div></footer><p class="sg-body" data-lager-edit-status aria-live="polite"></p></div></form>'
. '</div></div>'
. '</article>'
. '<div data-lager-drawer-topic="historical-lots" aria-label="Vergangene Chargen">' . auth_render_lager_historical_lots($lagerProducts) . '</div>'
. '<article class="sg-card sg-card--content-card" data-component="content-card" data-lager-drawer-topic="virtual-lot" aria-label="Virtuelle Charge">'
. '<div class="sg-card-segment sg-card-segment--header sg-card-segment--darkgreen" data-component-part="card-header"><div class="sg-strong sg-text-on-dark">Virtuelle Charge</div></div>'
. '<div class="sg-card-segment sg-card-segment--body" data-component-part="card-body"><p class="sg-body" data-lager-drawer-virtual-lot-value></p></div>'
. '</article>'
. '</div>'
. '</aside>'
. '</div>';
}
function render_auth_home_page(array $user, array $otcProducts = [], array $bestellungenTable = [], array $lagerProducts = [], array $lagerArtikel = [], array $lagerManufacturers = []): void
{
$otcProductRows = '';
foreach ($otcProducts as $product) {
$productId = (int) ($product['id'] ?? 0);
$productName = auth_escape_html((string) ($product['name'] ?? ''));
$productSku = auth_escape_html((string) ($product['sku'] ?? ''));
$availableQty = (int) max(0, (int) round((float) ($product['available_qty'] ?? 0)));
$hasSellableMapping = (bool) ($product['has_sellable_mapping'] ?? false);
$inputId = 'otc-product-' . $productId;
$mappingNote = $hasSellableMapping ? '' : ' (Artikel-Mapping fehlt)';
$disabledAttribute = $hasSellableMapping ? '' : ' disabled aria-disabled="true"';
$otcProductRows .= '<div class="sg-form-sections-card__field-group">';
$otcProductRows .= '<label class="sg-labeled-input-row sg-otc-order-product-row"><span class="sg-label">' . $productName . ($productSku !== '' ? ' (' . $productSku . ')' : '') . $mappingNote . '</span>';
$otcProductRows .= '<input class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable" type="number" id="' . $inputId . '" min="0" step="1" data-otc-order-product data-product-id="' . $productId . '" data-title="' . $productName . '" data-available-qty="' . $availableQty . '"' . $disabledAttribute . '>';
$otcProductRows .= '</label>';
$otcProductRows .= '</div>';
}
if ($otcProductRows === '') {
$otcProductRows = '<p class="sg-body sg-form-sections-card__sentence">Keine aktiven OTC-Produkte erfasst.</p>';
}
$moduleNavigation = json_encode(
[
'Übersicht' => [],
'ERP' => ['Bestellungen', 'Lager', 'Produkte', 'Artikel', 'Kontakte'],
'Buchhaltung' => [],
'Kundenberatung' => [],
],
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
);
$bestellungenContent = auth_render_bestellungen_content($bestellungenTable);
$lagerContent = auth_render_lager_content($lagerProducts, $lagerArtikel, $lagerManufacturers, auth_csrf_token());
$moduleContentCards = json_encode(
[
'Bestellungen' => $bestellungenContent,
'Lager' => $lagerContent,
'Artikel' => auth_render_lager_content([], $lagerArtikel, $lagerManufacturers, auth_csrf_token(), 'Artikel'),
],
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
);
$moduleHeadings = json_encode(
[
'Übersicht' => 'Willkommen bei Naurua Übersicht',
'ERP' => 'Willkommen bei Naurua ERP',
'Buchhaltung' => 'Willkommen bei Naurua Buchhaltung',
'Kundenberatung' => 'Willkommen bei Naurua Kundenberatung',
],
JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES
);
echo '<!doctype html>';
echo '<html lang="de">';
echo '<head>';
echo '<meta charset="UTF-8">';
echo '<meta name="viewport" content="width=device-width, initial-scale=1.0">';
echo '<title>Naurua ERP</title>';
echo '<link rel="stylesheet" href="/assets/styles.css">';
echo '<link rel="stylesheet" href="/assets/styles.portal.css?v=' . filemtime(__DIR__ . '/../../../../public/assets/styles.portal.css') . '">';
echo '</head>';
echo '<body>';
echo '<section id="pattern-portal-header" class="sg-vsf-list-overview-page-v2">';
echo '<article class="sg-portal-header-pattern-variant" aria-label="Portal Header">';
echo '<header class="sg-portal-header" aria-label="Portal Header" data-pattern="portal-header">';
echo '<div class="sg-portal-header__main" data-pattern-part="portal-header-main">';
echo '<p class="sg-portal-header__brand sg-brand-title" data-pattern-part="portal-header-brand">Naurua ERP</p>';
echo '<div class="sg-portal-header__menu-wrap sg-sandwich-menu-wrap" data-open="false" data-component="sandwich-menu" data-component-size="default" data-component-context="portal-header" data-pattern-part="portal-header-action">';
echo '<button class="sg-interaction-element sg-sandwich-button" type="button" aria-expanded="false" aria-label="Menü öffnen" data-component-part="sandwich-trigger">';
echo '<span class="sg-sandwich-button__icon" aria-hidden="true">';
echo '<span class="sg-sandwich-button__line"></span>';
echo '<span class="sg-sandwich-button__line"></span>';
echo '<span class="sg-sandwich-button__line"></span>';
echo '</span>';
echo '</button>';
echo '<div class="sg-sandwich-menu-panel" aria-label="Ausgeklapptes Menü" data-component-part="sandwich-panel">';
echo '<a class="sg-sandwich-menu-link" href="/" data-component-part="sandwich-menu-link">Startseite</a>';
echo '<a class="sg-sandwich-menu-link" href="/logout.php" data-component-part="sandwich-menu-link">Abmelden</a>';
echo '</div>';
echo '</div>';
echo '<nav class="sg-portal-header__tabs sg-tab-button-group" aria-label="Hauptnavigation" data-component="tab-navigation" data-component-size="large" data-component-context="portal-header" data-pattern-part="portal-header-navigation">';
echo '<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Übersicht</button>';
echo '<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="true" data-component-part="tab-button" data-component-state="active">ERP</button>';
echo '<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Buchhaltung</button>';
echo '<button class="sg-interaction-element sg-button sg-tab-button" type="button" aria-selected="false" data-component-part="tab-button" data-component-state="inactive">Kundenberatung</button>';
echo '</nav>';
echo '</div>';
echo '</header>';
echo '</article>';
echo '<div class="sg-transparent-card" data-component="transparent-card">';
echo '<h1 class="sg-main-heading" data-main-heading aria-live="polite">Willkommen bei Naurua ERP</h1>';
echo '</div>';
echo '<section class="sg-left-navigation-pattern" aria-label="Linke Navigation">';
echo '<div class="sg-left-navigation-pattern__layout" aria-label="Left Navigation Demo">';
echo '<aside class="sg-group-card sg-left-navigation-pattern__group-card sg-left-navigation-pattern__group-card--navigation" data-component="group-card" aria-label="Navigation">';
echo '<div class="sg-group-card__header-row sg-left-navigation-pattern__header-row">';
echo '<h2 class="sg-heading-h2 sg-text-on-dark sg-group-card__heading" data-left-navigation-title aria-live="polite">ERP</h2>';
echo '<button class="sg-interaction-element sg-button sg-button--active sg-left-navigation-pattern__toggle" type="button" data-left-navigation-toggle aria-expanded="true" aria-controls="left-navigation-menu">Ausblenden</button>';
echo '</div>';
echo '<nav class="sg-tab-button-group" id="left-navigation-menu" role="tablist" aria-label="Linksmenue Items" data-component="tab-navigation" data-component-size="large" data-component-variant="linksmenu-items">';
echo '<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="true" data-component-part="tab-button">Bestellungen</button>';
echo '<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button">Lager</button>';
echo '<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button">Produkte</button>';
echo '<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button">Artikel</button>';
echo '<button class="sg-interaction-element sg-button sg-tab-button" type="button" role="tab" aria-selected="false" data-component-part="tab-button">Kontakte</button>';
echo '</nav>';
echo '</aside>';
echo '<section class="sg-group-card sg-left-navigation-pattern__group-card sg-left-navigation-pattern__group-card--content" data-component="group-card" aria-hidden="true">';
echo '<div class="sg-group-card__header-row sg-left-navigation-pattern__header-row">';
echo '<h2 class="sg-heading-h2 sg-text-on-dark sg-group-card__heading" data-left-navigation-content-title aria-live="polite">Bestellungen</h2>';
echo '</div>';
echo '<div data-left-navigation-content-body>';
echo $bestellungenContent;
echo '</div>';
echo '</section>';
echo '</div>';
echo '</section>';
echo '</section>';
echo '<section class="sg-otc-order-overlay" data-otc-order-overlay data-open="false" aria-hidden="true">';
echo '<div class="sg-delete-confirmation-pattern__stage sg-delete-confirmation-pattern__host sg-object-card" data-pattern="overlay-card" data-dialog-open="false" data-otc-confirmation-stage>';
echo '<article class="sg-card sg-scrollable-card sg-delete-confirmation-pattern__target sg-otc-order-overlay__panel" data-pattern="scrollable-card" aria-labelledby="otc-order-modal-title" role="dialog" aria-modal="true">';
echo '<header class="sg-card-segment sg-card-segment--header sg-card-segment--darkblue sg-scrollable-card__header sg-object-card__header" data-pattern-part="scrollable-card-header">';
echo '<h2 id="otc-order-modal-title" class="sg-strong sg-otc-order-overlay__title">Neuen OTC-Verkauf erfassen</h2>';
echo '<button class="sg-interaction-element sg-button sg-button--active sg-otc-order-overlay__close" type="button" data-otc-order-close>Schliessen</button>';
echo '</header>';
echo '<div class="sg-card-segment sg-card-segment--gray sg-scrollable-card__content sg-object-card__content" data-pattern-part="scrollable-card-content" tabindex="0" aria-label="Scrollbarer Formularinhalt">';
echo '<div class="sg-form-sections-card-wrapper" data-pattern="form-sections" aria-label="Formular mit Abschnitten">';
echo '<form id="otc-order-form" class="sg-form-sections-card" action="#" method="post" data-otc-order-form aria-label="Neuen OTC-Verkauf erfassen">';
echo '<div class="sg-form-sections-card__body" data-pattern-part="form-body">';
echo '<section class="sg-form-sections-card__chapter" aria-labelledby="otc-products-title">';
echo '<h2 id="otc-products-title" class="sg-strong sg-form-sections-card__chapter-title">PRODUKTE</h2>';
echo $otcProductRows;
echo '</section>';
echo '<section class="sg-form-sections-card__chapter" aria-labelledby="otc-order-date-title">';
echo '<h2 id="otc-order-date-title" class="sg-strong sg-form-sections-card__chapter-title">Datum</h2>';
echo '<div class="sg-form-sections-card__field-group">';
echo '<label class="sg-labeled-input-row"><span class="sg-label">Bestelldatum</span>';
echo '<input class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable" type="date" id="otc-order-date" value="' . htmlspecialchars(date('Y-m-d'), ENT_QUOTES, 'UTF-8') . '" data-otc-order-date>';
echo '</label>';
echo '</div>';
echo '</section>';
echo '<section class="sg-form-sections-card__chapter" aria-labelledby="otc-payment-title">';
echo '<h2 id="otc-payment-title" class="sg-strong sg-form-sections-card__chapter-title">Bezahlung</h2>';
echo '<div data-otc-payment-rows>';
echo '<div class="sg-form-sections-card__field-group" data-otc-payment-row>';
echo '<label class="sg-labeled-input-row"><span class="sg-label">Bezahlart</span>';
echo '<select class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable sg-pulldown" id="otc-payment-method-1" data-otc-payment-method>';
echo '<option value="twint">Twint</option><option value="card">Kreditkarte</option><option value="cash">Barzahlung</option><option value="paypal">PayPal</option><option value="bank_transfer">Überweisung</option>';
echo '</select>';
echo '</label>';
echo '<label class="sg-labeled-input-row"><span class="sg-label">Betrag (CHF)</span>';
echo '<input class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable" type="number" id="otc-payment-amount-1" min="0.01" step="0.01" value="0.00" data-otc-payment-amount>';
echo '</label>';
echo '</div>';
echo '</div>';
echo '<div class="sg-form-sections-card__actions-segment">';
echo '<button class="sg-interaction-element sg-button sg-button--active" type="button" data-otc-payment-add>Bezahlart hinzufügen</button>';
echo '</div>';
echo '</section>';
echo '<section class="sg-form-sections-card__chapter" aria-labelledby="otc-billing-title">';
echo '<h2 id="otc-billing-title" class="sg-strong sg-form-sections-card__chapter-title">Rechnungsadresse</h2>';
echo '<div class="sg-form-sections-card__field-group">';
echo '<label class="sg-labeled-input-row"><span class="sg-label">Vorname</span>';
echo '<input class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable" type="text" id="otc-first-name" value="Fabienne" data-otc-order-first-name>';
echo '</label>';
echo '</div>';
echo '<div class="sg-form-sections-card__field-group">';
echo '<label class="sg-labeled-input-row"><span class="sg-label">Nachname</span>';
echo '<input class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable" type="text" id="otc-last-name" value="Föhn" data-otc-order-last-name>';
echo '</label>';
echo '</div>';
echo '<div class="sg-form-sections-card__field-group">';
echo '<label class="sg-labeled-input-row"><span class="sg-label">Strasse</span>';
echo '<input class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable" type="text" id="otc-street" value="Im Hochrain" data-otc-order-street>';
echo '</label>';
echo '</div>';
echo '<div class="sg-form-sections-card__field-group">';
echo '<label class="sg-labeled-input-row"><span class="sg-label">Hausnummer</span>';
echo '<input class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable" type="text" id="otc-house-number" value="2" data-otc-order-house-number>';
echo '</label>';
echo '</div>';
echo '<div class="sg-form-sections-card__field-group">';
echo '<label class="sg-labeled-input-row"><span class="sg-label">PLZ</span>';
echo '<input class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable" type="text" id="otc-zip" value="8102" data-otc-order-zip>';
echo '</label>';
echo '</div>';
echo '<div class="sg-form-sections-card__field-group">';
echo '<label class="sg-labeled-input-row"><span class="sg-label">Ort</span>';
echo '<input class="sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable" type="text" id="otc-city" value="Oberengstringen" data-otc-order-city>';
echo '</label>';
echo '</div>';
echo '<div class="sg-form-sections-card__field-group">';
echo '<div class="sg-body sg-otc-order-form__status hidden" data-otc-order-success>Bestellung erfolgreich erfasst! Die Bestellnummer wird automatisch generiert.</div>';
echo '<div class="sg-body sg-otc-order-form__status sg-otc-order-form__status--error hidden" data-otc-order-error></div>';
echo '</div>';
echo '</div>';
echo '</form>';
echo '</div>';
echo '</div>';
echo '<footer class="sg-card-segment sg-card-segment--body sg-scrollable-card__actions-segment" data-pattern-part="scrollable-card-actions">';
echo '<div class="sg-scrollable-card__actions">';
echo '<button class="sg-interaction-element sg-button sg-button--active" type="button" form="otc-order-form" data-otc-order-close>Abbrechen</button>';
echo '<button class="sg-interaction-element sg-button sg-button--process sg-button--process-inactive" type="submit" form="otc-order-form" disabled aria-disabled="true" data-otc-order-submit>Weiter</button>';
echo '</div>';
echo '</footer>';
echo '</article>';
echo '<article class="sg-card sg-card--overlay-host sg-delete-confirmation-pattern__floating-card" aria-label="Verkaufsbestätigung" role="dialog" aria-modal="true" aria-labelledby="otc-confirmation-title" data-otc-confirmation-card hidden>';
echo '<div class="sg-card-segment sg-card-segment--body sg-delete-confirmation-pattern__body">';
echo '<p class="sg-body sg-delete-confirmation-pattern__text" id="otc-confirmation-title"><strong>Verkauf bestätigen</strong></p>';
echo '<div class="sg-delete-confirmation-pattern__list" data-otc-confirmation-products aria-label="Produkte"></div>';
echo '<p class="sg-body sg-delete-confirmation-pattern__text"><strong>Gesamtzahl Flaschen: <span data-otc-confirmation-quantity>0</span></strong></p>';
echo '<p class="sg-body sg-delete-confirmation-pattern__text"><strong>Gesamtbetrag: CHF <span data-otc-confirmation-total>0.00</span></strong></p>';
echo '<div class="sg-delete-confirmation-pattern__actions">';
echo '<button class="sg-interaction-element sg-button sg-button--active" type="button" data-otc-confirmation-cancel>Abbrechen</button>';
echo '<button class="sg-interaction-element sg-button sg-button--process" type="button" data-otc-confirmation-submit>Verkaufen</button>';
echo '</div>';
echo '</div>';
echo '</article>';
echo '</div>';
echo '</section>';
echo '<script src="/scripts/help-icon-overlays.js"></script>';
echo '<script>';
echo 'const portalModuleNavigation = ' . $moduleNavigation . ';';
echo 'const portalModuleContentCards = ' . $moduleContentCards . ';';
echo 'const portalModuleHeadings = ' . $moduleHeadings . ';';
echo "const renderMainHeading = (moduleName) => {";
echo " const heading = document.querySelector('[data-main-heading]');";
echo " if (heading && portalModuleHeadings[moduleName]) { heading.textContent = portalModuleHeadings[moduleName]; }";
echo "};";
echo "const renderLeftNavigation = (moduleName) => {";
echo " const title = document.querySelector('[data-left-navigation-title]');";
echo " const contentTitle = document.querySelector('[data-left-navigation-content-title]');";
echo " const contentBody = document.querySelector('[data-left-navigation-content-body]');";
echo " const menu = document.getElementById('left-navigation-menu');";
echo " if (title) { title.textContent = moduleName; }";
echo " if (!menu) { return; }";
echo " const entries = portalModuleNavigation[moduleName] || [];";
echo " const activeEntry = entries[0] || '';";
echo " if (contentTitle) { contentTitle.textContent = activeEntry; }";
echo " if (contentBody) { contentBody.innerHTML = portalModuleContentCards[activeEntry] || ''; }";
echo " if (activeEntry === 'Bestellungen') { initBestellungenBindings(); }";
echo " if (activeEntry === 'Lager' || activeEntry === 'Artikel') { initLagerBindings(); }";
echo " menu.innerHTML = '';";
echo " entries.forEach((entry, index) => {";
echo " const button = document.createElement('button');";
echo " button.className = 'sg-interaction-element sg-button sg-tab-button';";
echo " button.type = 'button';";
echo " button.setAttribute('role', 'tab');";
echo " button.setAttribute('data-component-part', 'tab-button');";
echo " button.setAttribute('aria-selected', String(index === 0));";
echo " button.textContent = entry;";
echo " menu.appendChild(button);";
echo " });";
echo " menu.querySelectorAll('.sg-tab-button').forEach((button) => {";
echo " button.addEventListener('click', () => {";
echo " menu.querySelectorAll('.sg-tab-button').forEach((otherButton) => {";
echo " otherButton.setAttribute('aria-selected', String(otherButton === button));";
echo " });";
echo " const entryName = button.textContent.trim();";
echo " if (contentTitle) { contentTitle.textContent = entryName; }";
echo " if (contentBody) { contentBody.innerHTML = portalModuleContentCards[entryName] || ''; }";
echo " if (entryName === 'Bestellungen') { initBestellungenBindings(); }";
echo " if (entryName === 'Lager' || entryName === 'Artikel') { initLagerBindings(); }";
echo " });";
echo " });";
echo "};";
echo "document.querySelectorAll('.sg-portal-header__tabs').forEach((group) => {";
echo " group.querySelectorAll('.sg-tab-button').forEach((button) => {";
echo " button.addEventListener('click', () => {";
echo " group.querySelectorAll('.sg-tab-button').forEach((otherButton) => {";
echo " const isActive = otherButton === button;";
echo " otherButton.setAttribute('aria-selected', String(isActive));";
echo " otherButton.dataset.componentState = isActive ? 'active' : 'inactive';";
echo " });";
echo " renderMainHeading(button.textContent.trim());";
echo " renderLeftNavigation(button.textContent.trim());";
echo " });";
echo " });";
echo "});";
echo "document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {";
echo " const button = wrap.querySelector('.sg-sandwich-button');";
echo " button.addEventListener('click', (event) => {";
echo " event.stopPropagation();";
echo " const nextState = wrap.dataset.open !== 'true';";
echo " document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((otherWrap) => {";
echo " const otherButton = otherWrap.querySelector('.sg-sandwich-button');";
echo " otherWrap.dataset.open = 'false';";
echo " if (otherButton) { otherButton.setAttribute('aria-expanded', 'false'); }";
echo " });";
echo " wrap.dataset.open = String(nextState);";
echo " button.setAttribute('aria-expanded', String(nextState));";
echo " });";
echo "});";
echo "document.addEventListener('click', (event) => {";
echo " if (event.target.closest('.sg-sandwich-menu-wrap')) {";
echo " return;";
echo " }";
echo " document.querySelectorAll('.sg-sandwich-menu-wrap').forEach((wrap) => {";
echo " const button = wrap.querySelector('.sg-sandwich-button');";
echo " wrap.dataset.open = 'false';";
echo " if (button) { button.setAttribute('aria-expanded', 'false'); }";
echo " });";
echo "});";
echo "(() => {";
echo " const mediaQuery = window.matchMedia('(max-width: 767px)');";
echo " const toggle = document.querySelector('[data-left-navigation-toggle]');";
echo " const menu = document.getElementById('left-navigation-menu');";
echo " if (!toggle || !menu) { return; }";
echo " const setMenuState = (expanded) => {";
echo " menu.hidden = !expanded;";
echo " menu.classList.toggle('sg-left-navigation-pattern__menu--collapsed', !expanded);";
echo " toggle.setAttribute('aria-expanded', String(expanded));";
echo " toggle.textContent = expanded ? 'Ausblenden' : 'Einblenden';";
echo " toggle.classList.add('sg-button--active');";
echo " toggle.classList.remove('sg-button--inactive');";
echo " };";
echo " const syncMode = () => {";
echo " if (mediaQuery.matches) {";
echo " if (toggle.getAttribute('aria-expanded') !== 'true' && toggle.getAttribute('aria-expanded') !== 'false') { setMenuState(true); return; }";
echo " setMenuState(toggle.getAttribute('aria-expanded') !== 'false');";
echo " return;";
echo " }";
echo " menu.hidden = false;";
echo " menu.classList.remove('sg-left-navigation-pattern__menu--collapsed');";
echo " toggle.setAttribute('aria-expanded', 'true');";
echo " toggle.textContent = 'Ausblenden';";
echo " toggle.classList.add('sg-button--active');";
echo " toggle.classList.remove('sg-button--inactive');";
echo " };";
echo " toggle.addEventListener('click', () => { setMenuState(menu.hidden); });";
echo " menu.querySelectorAll('.sg-tab-button').forEach((button) => {";
echo " button.addEventListener('click', () => {";
echo " menu.querySelectorAll('.sg-tab-button').forEach((otherButton) => {";
echo " otherButton.setAttribute('aria-selected', String(otherButton === button));";
echo " });";
echo " });";
echo " });";
echo " syncMode();";
echo " mediaQuery.addEventListener('change', syncMode);";
echo "})();";
echo "let bestellungenTableHandlersInstalled = false;";
echo "let lagerBindingsInstalled = false;";
echo "function initLagerBindings() {";
echo " if (lagerBindingsInstalled) { return; }";
echo " const contentRoot = document.querySelector('[data-left-navigation-content-body]');";
echo " if (!contentRoot || !contentRoot.querySelector('[data-lager-content]')) { return; }";
echo " lagerBindingsInstalled = true;";
echo " let lagerMobileDetailHost = null;";
echo " let lagerMobileDetailOpen = false;";
echo <<<'JS'
const renderLagerMobileDetail = () => { const sourceDrawer = contentRoot.querySelector('[data-lager-drawer]'); if (!sourceDrawer) { return ''; } return `<div class="sg-lager-mobile-detail-host" data-lager-mobile-detail-host="true"><div class="sg-navigation-card-layout sg-mobile-detail-back-card"><div class="sg-navigation-card-block"><article class="sg-card" data-component="card" data-pattern="navigation-card" aria-label="Navigation Detailansicht zurück oben"><div class="sg-card-segment sg-card-segment--body" data-component-part="card-body" data-pattern-part="navigation-card-segment"><div class="sg-navigation-card-center"><button class="sg-interaction-element sg-hyperlink" type="button" data-lager-detail-back>zurück</button></div></div></article></div></div>${sourceDrawer.outerHTML.replace('data-lager-drawer="true"', 'data-lager-drawer="true" data-lager-mobile-drawer="true"')}</div>`; };
JS;
echo " const restoreLagerMobileDetail = () => {";
echo " if (lagerMobileDetailHost && lagerMobileDetailHost.parentNode) { lagerMobileDetailHost.parentNode.removeChild(lagerMobileDetailHost); }";
echo " const sourceDrawer = contentRoot.querySelector('[data-lager-drawer]:not([data-lager-mobile-drawer])'); if (sourceDrawer) { sourceDrawer.dataset.open = 'false'; sourceDrawer.setAttribute('aria-hidden', 'true'); }";
echo " lagerMobileDetailHost = null; lagerMobileDetailOpen = false; document.body.classList.remove('sg-lager-mobile-detail-open');";
echo " };";
echo " const closeLagerMobileDetail = () => {";
echo " if (!lagerMobileDetailOpen) { return; }";
echo " if (window.history.state && window.history.state.lagerView === 'detail') { window.history.back(); return; }";
echo " restoreLagerMobileDetail();";
echo " };";
echo " const getDrawer = () => contentRoot.querySelector('[data-lager-mobile-drawer]') || contentRoot.querySelector('[data-lager-drawer]');";
echo " const setDrawerState = (open) => {";
echo " const drawer = getDrawer(); const backdrop = contentRoot.querySelector('[data-lager-drawer-backdrop]');";
echo " if (!drawer || !backdrop) { return; }";
echo " drawer.dataset.open = String(open); drawer.setAttribute('aria-hidden', String(!open)); backdrop.dataset.open = String(open); backdrop.setAttribute('aria-hidden', String(!open)); document.body.classList.toggle('sg-card-list-page-drawer-open', open);";
echo " };";
echo " const getLagerWarningTitle = (trigger) => trigger.dataset.lagerDrawerForecastStatus === 'depleted' ? 'Warnung: Charge ist aufgebraucht' : (trigger.dataset.lagerDrawerForecastMhdWarning === 'true' ? 'Warnung: MHD wird vor Chargenende erreicht' : (trigger.dataset.lagerDrawerForecastWarning === 'true' ? 'Warnung: Charge wird innerhalb von drei Monaten aufgebraucht sein' : 'Keine Warnung'));";
echo " const closeDrawer = () => { setDrawerState(false); contentRoot.querySelectorAll('[data-lager-drawer-open]').forEach((trigger) => trigger.setAttribute('aria-expanded', 'false')); };";
echo " contentRoot.addEventListener('click', (event) => {";
echo " const trigger = event.target.closest('[data-lager-drawer-open]');";
echo " if (trigger) { event.preventDefault(); if (window.matchMedia('(max-width: 767px)').matches) { restoreLagerMobileDetail(); } const drawer = getDrawer(); if (!drawer) { return; } const type = trigger.dataset.lagerDrawerType || 'Lager'; const name = trigger.dataset.lagerDrawerName || ''; const value = trigger.dataset.lagerDrawerValue || ''; drawer.querySelector('[data-lager-drawer-title]').textContent = type + ': ' + name; drawer.querySelector('[data-lager-drawer-name-value]').textContent = name; const valueRow = drawer.querySelector('[data-lager-drawer-value-row]'); if (valueRow) { valueRow.hidden = false; } drawer.querySelector('[data-lager-drawer-value-label]').textContent = type === 'Produkt' ? 'Anzahl im Lager:' : 'Artikelnummer:'; drawer.querySelector('[data-lager-drawer-value-value]').textContent = value; drawer.querySelectorAll('[data-lager-drawer-topic]').forEach((card) => { card.hidden = type !== 'Produkt'; }); if (type === 'Produkt') { const forecast = trigger.dataset.lagerDrawerForecast || 'Keine Prognose'; const warning = trigger.dataset.lagerDrawerForecastWarning === 'true' || trigger.dataset.lagerDrawerForecastMhdWarning === 'true'; const warningValue = drawer.querySelector('[data-lager-drawer-warning-value]'); if (warningValue) { warningValue.textContent = warning ? forecast : 'Keine akute Warnung.'; warningValue.classList.toggle('sg-strong', warning); warningValue.classList.toggle('lager-forecast-warning', trigger.dataset.lagerDrawerForecastWarning === 'true'); warningValue.classList.toggle('lager-forecast-mhd-warning', trigger.dataset.lagerDrawerForecastMhdWarning === 'true'); } drawer.querySelector('[data-lager-drawer-lot-number]').textContent = trigger.dataset.lagerDrawerLotNumber || 'Nicht hinterlegt'; drawer.querySelector('[data-lager-drawer-manufacturer-name]').textContent = trigger.dataset.lagerDrawerManufacturerName || 'Nicht hinterlegt'; drawer.querySelector('[data-lager-drawer-manufacturer-lot-number]').textContent = trigger.dataset.lagerDrawerManufacturerLotNumber || 'Nicht hinterlegt'; drawer.querySelector('[data-lager-drawer-mfg-date]').textContent = trigger.dataset.lagerDrawerMfgDate || 'Nicht hinterlegt'; drawer.querySelector('[data-lager-drawer-expiry-date]').textContent = trigger.dataset.lagerDrawerExpiryDate || 'Nicht hinterlegt'; drawer.querySelector('[data-lager-drawer-purchase-date]').textContent = trigger.dataset.lagerDrawerPurchaseDate || 'Nicht hinterlegt'; const virtualLot = trigger.dataset.lagerDrawerVirtualLotNumber || ''; drawer.querySelector('[data-lager-drawer-virtual-lot-value]').textContent = virtualLot ? 'Virtuelle Charge: ' + virtualLot : 'Keine virtuelle Fehlbestandscharge vorhanden.'; const manufacturer = drawer.querySelector('[data-lager-manufacturer]'); if (manufacturer) { manufacturer.value = trigger.dataset.lagerDrawerManufacturerPartyId || ''; } const manufacturerLot = drawer.querySelector('[data-lager-manufacturer-lot]'); if (manufacturerLot) { manufacturerLot.value = trigger.dataset.lagerDrawerManufacturerLotNumber || ''; } const mfgDate = drawer.querySelector('[data-lager-mfg-date]'); if (mfgDate) { mfgDate.value = trigger.dataset.lagerDrawerMfgDate || ''; } const expiryDate = drawer.querySelector('[data-lager-expiry-date]'); if (expiryDate) { expiryDate.value = trigger.dataset.lagerDrawerExpiryDate || ''; } const purchaseDate = drawer.querySelector('[data-lager-purchase-date]'); if (purchaseDate) { purchaseDate.value = trigger.dataset.lagerDrawerPurchaseDate || ''; } const editForm = drawer.querySelector('[data-lager-edit-form]'); if (editForm) { editForm.hidden = true; } drawer.dataset.lagerActiveLotId = trigger.dataset.lagerDrawerLotId || ''; } setDrawerState(true); contentRoot.querySelectorAll('[data-lager-drawer-open]').forEach((button) => button.setAttribute('aria-expanded', String(button === trigger))); return; }";
echo " if (event.target.closest('[data-lager-drawer-close]') || event.target.closest('[data-lager-drawer-backdrop]')) { closeDrawer(); }";
echo " });";
echo " contentRoot.addEventListener('click', (event) => { const trigger = event.target.closest('[data-lager-drawer-open]'); if (!trigger || trigger.dataset.lagerDrawerType !== 'Produkt') { return; } const header = getDrawer()?.querySelector('[data-lager-drawer-warning-header]'); const title = getDrawer()?.querySelector('[data-lager-drawer-warning-title]'); if (!header || !title) { return; } const forecastWarning = trigger.dataset.lagerDrawerForecastWarning === 'true'; const mhdWarning = trigger.dataset.lagerDrawerForecastMhdWarning === 'true'; title.textContent = getLagerWarningTitle(trigger); header.classList.toggle('sg-card-segment--darkgreen', !forecastWarning && !mhdWarning); header.classList.toggle('sg-card-segment--signal-red', forecastWarning); header.classList.toggle('sg-card-segment--signal-yellow', mhdWarning); });";
echo " contentRoot.addEventListener('click', (event) => { const trigger = event.target.closest('[data-lager-drawer-open]'); if (!trigger || trigger.dataset.lagerDrawerType !== 'Produkt') { return; } setLagerEditMode(false); const drawer = getDrawer(); const currentQty = drawer?.querySelector('[data-lager-drawer-current-qty]'); const qtyIn = drawer?.querySelector('[data-lager-drawer-qty-in]'); const lotNumber = drawer?.querySelector('[data-lager-lot-number]'); if (currentQty) { currentQty.textContent = trigger.dataset.lagerDrawerCurrentQty || '0'; } if (qtyIn) { qtyIn.textContent = trigger.dataset.lagerDrawerQtyIn || '0'; } if (lotNumber) { lotNumber.value = trigger.dataset.lagerDrawerLotNumber || ''; } const productId = trigger.closest('[data-lager-row]')?.dataset.lagerId || ''; drawer?.querySelectorAll('[data-lager-historical-product]').forEach((product) => { product.hidden = product.dataset.lagerHistoricalProduct !== productId; }); });";
echo " contentRoot.addEventListener('click', (event) => { const trigger = event.target.closest('[data-lager-drawer-open]'); if (trigger && window.matchMedia('(max-width: 767px)').matches) { const host = document.createElement('div'); host.innerHTML = renderLagerMobileDetail(); lagerMobileDetailHost = host.firstElementChild; const mobileDrawer = lagerMobileDetailHost?.querySelector('[data-lager-mobile-drawer]'); if (lagerMobileDetailHost && mobileDrawer) { contentRoot.appendChild(lagerMobileDetailHost); mobileDrawer.dataset.open = 'true'; mobileDrawer.setAttribute('aria-hidden', 'false'); lagerMobileDetailOpen = true; document.body.classList.add('sg-lager-mobile-detail-open'); } return; } if (event.target.closest('[data-lager-detail-back]') || (event.target.closest('[data-lager-drawer-close]') && lagerMobileDetailOpen)) { restoreLagerMobileDetail(); } });";
echo " const postLagerChange = async (payload) => { const response = await fetch('/api/lager-charge.php', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ ...payload, csrfToken: contentRoot.querySelector('[data-lager-csrf-token]')?.dataset.lagerCsrfToken || '' }) }); const result = await response.json(); if (!response.ok || result.ok !== true) { throw new Error(result.error || 'Speichern fehlgeschlagen'); } return result; };";
echo " contentRoot.addEventListener('click', (event) => { const editButton = event.target.closest('[data-lager-edit-open]'); if (editButton) { const drawer = getDrawer(); const editForm = drawer?.querySelector('[data-lager-edit-form]'); if (editForm) { editForm.hidden = false; } return; } const closeButton = event.target.closest('[data-lager-edit-close]'); if (closeButton) { const drawer = getDrawer(); const editForm = drawer?.querySelector('[data-lager-edit-form]'); if (editForm) { editForm.hidden = true; } } });";
echo " const setLagerEditMode = (editing) => { const drawer = getDrawer(); const readView = drawer?.querySelector('[data-lager-read-view]'); const editForm = drawer?.querySelector('[data-lager-edit-form]'); if (readView) { readView.hidden = editing; } if (editForm) { editForm.hidden = !editing; } };";
echo " contentRoot.addEventListener('click', (event) => { if (event.target.closest('[data-lager-edit-open]')) { setLagerEditMode(true); } if (event.target.closest('[data-lager-edit-close]')) { clearLagerMovementInputs(); setLagerEditMode(false); } });";
echo " const syncLagerReadView = () => { const drawer = getDrawer(); if (!drawer) { return; } const manufacturer = drawer.querySelector('[data-lager-manufacturer]'); const values = { '[data-lager-drawer-manufacturer-name]': manufacturer?.selectedOptions?.[0]?.textContent || 'Nicht hinterlegt', '[data-lager-drawer-manufacturer-lot-number]': drawer.querySelector('[data-lager-manufacturer-lot]')?.value || 'Nicht hinterlegt', '[data-lager-drawer-mfg-date]': drawer.querySelector('[data-lager-mfg-date]')?.value || 'Nicht hinterlegt', '[data-lager-drawer-expiry-date]': drawer.querySelector('[data-lager-expiry-date]')?.value || 'Nicht hinterlegt', '[data-lager-drawer-purchase-date]': drawer.querySelector('[data-lager-purchase-date]')?.value || 'Nicht hinterlegt' }; Object.entries(values).forEach(([selector, value]) => { const target = drawer.querySelector(selector); if (target) { target.textContent = value; } }); const trigger = contentRoot.querySelector('[data-lager-drawer-open][aria-expanded=\"true\"]'); if (trigger) { trigger.dataset.lagerDrawerManufacturerName = values['[data-lager-drawer-manufacturer-name]']; trigger.dataset.lagerDrawerManufacturerLotNumber = values['[data-lager-drawer-manufacturer-lot-number]']; trigger.dataset.lagerDrawerMfgDate = values['[data-lager-drawer-mfg-date]']; trigger.dataset.lagerDrawerExpiryDate = values['[data-lager-drawer-expiry-date]']; trigger.dataset.lagerDrawerPurchaseDate = values['[data-lager-drawer-purchase-date]']; } };";
echo " const syncLagerBalanceView = (balance) => { const drawer = getDrawer(); if (!drawer || !balance) { return; } const currentQty = drawer.querySelector('[data-lager-drawer-current-qty]'); const qtyIn = drawer.querySelector('[data-lager-drawer-qty-in]'); if (currentQty) { currentQty.textContent = String(balance.qty_net ?? 0); } if (qtyIn) { qtyIn.textContent = String(balance.qty_in ?? 0); } const trigger = contentRoot.querySelector('[data-lager-drawer-open][aria-expanded=\"true\"]'); if (trigger) { trigger.dataset.lagerDrawerCurrentQty = String(balance.qty_net ?? 0); trigger.dataset.lagerDrawerQtyIn = String(balance.qty_in ?? 0); } };";
echo " const clearLagerMovementInputs = () => { const drawer = getDrawer(); if (!drawer) { return; } drawer.querySelectorAll('[data-lager-receipt-qty], [data-lager-adjustment-qty], [data-lager-out-qty]').forEach((input) => { input.value = ''; }); };";
echo " const syncLagerOpenLotCard = (lot, balance) => { const drawer = getDrawer(); const card = drawer?.querySelector('[data-lager-open-card=\"' + (lot?.id || '') + '\"]'); if (!card) { return; } const values = { '[data-lager-open-card-lot-number]': lot?.lot_number || 'Nicht hinterlegt', '[data-lager-open-card-qty-net]': String(balance?.qty_net ?? 0), '[data-lager-open-card-qty-in]': String(balance?.qty_in ?? 0), '[data-lager-open-card-manufacturer]': drawer.querySelector('[data-lager-new-manufacturer]')?.selectedOptions?.[0]?.textContent || 'Nicht hinterlegt', '[data-lager-open-card-manufacturer-lot]': lot?.manufacturer_lot_number || 'Nicht hinterlegt', '[data-lager-open-card-mfg-date]': lot?.mfg_date || 'Nicht hinterlegt', '[data-lager-open-card-expiry-date]': lot?.expiry_date || 'Nicht hinterlegt', '[data-lager-open-card-purchase-date]': lot?.purchase_date || 'Nicht hinterlegt' }; Object.entries(values).forEach(([selector, value]) => { const target = card.querySelector(selector); if (target) { target.textContent = value; } }); };";
echo " contentRoot.addEventListener('click', (event) => { const trigger = event.target.closest('[data-lager-drawer-open]'); if (!trigger || trigger.dataset.lagerDrawerType !== 'Produkt') { return; } const drawer = getDrawer(); const productId = trigger.closest('[data-lager-row]')?.dataset.lagerId || ''; const openProduct = drawer?.querySelector('[data-lager-open-product=\"' + productId + '\"]'); drawer?.querySelectorAll('[data-lager-open-product]').forEach((product) => { product.hidden = product !== openProduct; product.querySelectorAll('[data-lager-open-edit-form]').forEach((form) => { form.hidden = true; }); product.querySelectorAll('[data-lager-open-card]').forEach((readView) => { readView.hidden = false; }); }); const newForm = drawer?.querySelector('[data-lager-drawer-topic=\"new-lot-form\"]'); const newAction = drawer?.querySelector('[data-lager-drawer-topic=\"new-lot-action\"]'); if (newForm) { newForm.hidden = true; } if (newAction) { newAction.hidden = false; } const notificationWrapper = drawer?.querySelector('[data-lager-new-lot-notification-wrapper]'); const notification = drawer?.querySelector('[data-lager-new-lot-notification]'); const shortageQty = trigger.dataset.lagerDrawerVirtualShortageQty || '0'; const hasShortage = shortageQty !== '0' && shortageQty !== '0,00'; if (notificationWrapper) { notificationWrapper.hidden = !hasShortage; } if (notification && hasShortage) { notification.textContent = 'Für dieses Produkt bestehen virtuelle Fehlbestände in Höhe von ' + shortageQty + '. Die Eingangsmenge wird nach Aktivierung der Charge zur Nachallokation verwendet.'; } const setValue = (selector, value) => { const field = drawer?.querySelector(selector); if (field) { field.value = value || ''; } }; setValue('[data-lager-new-lot-number]', trigger.dataset.lagerOpenLotNumber); setValue('[data-lager-new-manufacturer]', trigger.dataset.lagerOpenManufacturerPartyId); setValue('[data-lager-new-manufacturer-lot]', trigger.dataset.lagerOpenManufacturerLotNumber); setValue('[data-lager-new-mfg-date]', trigger.dataset.lagerOpenMfgDate); setValue('[data-lager-new-expiry-date]', trigger.dataset.lagerOpenExpiryDate); setValue('[data-lager-new-purchase-date]', trigger.dataset.lagerOpenPurchaseDate); if (drawer) { drawer.dataset.lagerOpenLotId = trigger.dataset.lagerOpenLotId || ''; drawer.dataset.lagerProductId = productId; } });";
echo " contentRoot.addEventListener('click', (event) => { const openButton = event.target.closest('[data-lager-new-lot-open]'); if (openButton) { const drawer = getDrawer(); const form = drawer?.querySelector('[data-lager-drawer-topic=\"new-lot-form\"]'); const action = drawer?.querySelector('[data-lager-drawer-topic=\"new-lot-action\"]'); if (form) { form.hidden = false; } if (action) { action.hidden = true; } return; } if (event.target.closest('[data-lager-new-lot-close]')) { const drawer = getDrawer(); const form = drawer?.querySelector('[data-lager-drawer-topic=\"new-lot-form\"]'); const action = drawer?.querySelector('[data-lager-drawer-topic=\"new-lot-action\"]'); if (form) { form.hidden = true; } if (action) { action.hidden = false; } } });";
echo " contentRoot.addEventListener('click', (event) => { const editButton = event.target.closest('[data-lager-open-edit-open]'); if (editButton) { const card = editButton.closest('[data-lager-open-card-wrapper]'); const form = card?.querySelector('[data-lager-open-edit-form]'); const readView = card?.querySelector('[data-lager-open-card]'); if (form) { form.hidden = false; } if (readView) { readView.hidden = true; } return; } const closeButton = event.target.closest('[data-lager-open-edit-close]'); if (closeButton) { const card = closeButton.closest('[data-lager-open-card-wrapper]'); const form = card?.querySelector('[data-lager-open-edit-form]'); const readView = card?.querySelector('[data-lager-open-card]'); if (form) { form.hidden = true; } if (readView) { readView.hidden = false; } } });";
echo " contentRoot.addEventListener('submit', async (event) => { const openLotForm = event.target.closest('[data-lager-open-edit-form-element]'); if (!openLotForm) { return; } event.preventDefault(); const drawer = getDrawer(); const card = openLotForm.closest('[data-lager-open-card-wrapper]'); const status = openLotForm.querySelector('[data-lager-open-edit-status]'); if (status) { status.textContent = 'Speichern läuft …'; } try { const result = await postLagerChange({ action: 'prepare_lot', productId: drawer?.dataset.lagerProductId || '', lotId: card?.dataset.lagerOpenCardWrapper || '', lotNumber: openLotForm.querySelector('[data-lager-open-lot-number]')?.value || '', manufacturerPartyId: openLotForm.querySelector('[data-lager-open-manufacturer]')?.value || null, manufacturerLotNumber: openLotForm.querySelector('[data-lager-open-manufacturer-lot]')?.value || '', mfgDate: openLotForm.querySelector('[data-lager-open-mfg-date]')?.value || '', expiryDate: openLotForm.querySelector('[data-lager-open-expiry-date]')?.value || '', purchaseDate: openLotForm.querySelector('[data-lager-open-purchase-date]')?.value || '', receiptQty: openLotForm.querySelector('[data-lager-open-receipt-qty]')?.value || '' }); syncLagerOpenLotCard(result.lot, result.balance); openLotForm.querySelector('[data-lager-open-receipt-qty]').value = ''; openLotForm.setAttribute('hidden', 'hidden'); card?.querySelector('[data-lager-open-card]')?.removeAttribute('hidden'); if (status) { status.textContent = ''; } } catch (error) { if (status) { status.textContent = error instanceof Error ? error.message : 'Speichern fehlgeschlagen'; } } });";
echo " contentRoot.addEventListener('submit', async (event) => { const newLotForm = event.target.closest('[data-lager-new-lot-form-element]'); if (!newLotForm) { return; } event.preventDefault(); const drawer = getDrawer(); const status = drawer?.querySelector('[data-lager-new-lot-status]'); if (status) { status.textContent = 'Speichern läuft …'; } try { const result = await postLagerChange({ action: 'prepare_lot', productId: drawer?.dataset.lagerProductId || '', lotId: drawer?.dataset.lagerOpenLotId || '', lotNumber: drawer?.querySelector('[data-lager-new-lot-number]')?.value || '', manufacturerPartyId: drawer?.querySelector('[data-lager-new-manufacturer]')?.value || null, manufacturerLotNumber: drawer?.querySelector('[data-lager-new-manufacturer-lot]')?.value || '', mfgDate: drawer?.querySelector('[data-lager-new-mfg-date]')?.value || '', expiryDate: drawer?.querySelector('[data-lager-new-expiry-date]')?.value || '', purchaseDate: drawer?.querySelector('[data-lager-new-purchase-date]')?.value || '', receiptQty: drawer?.querySelector('[data-lager-new-receipt-qty]')?.value || '' }); syncLagerOpenLotCard(result.lot, result.balance); const form = drawer?.querySelector('[data-lager-drawer-topic=\"new-lot-form\"]'); const action = drawer?.querySelector('[data-lager-drawer-topic=\"new-lot-action\"]'); if (form) { form.hidden = true; } if (action) { action.hidden = false; } if (status) { status.textContent = ''; } } catch (error) { if (status) { status.textContent = error instanceof Error ? error.message : 'Speichern fehlgeschlagen'; } } });";
echo " contentRoot.addEventListener('submit', async (event) => { const editForm = event.target.closest('[data-lager-edit-form-element]'); if (!editForm) { return; } event.preventDefault(); const drawer = getDrawer(); const status = drawer?.querySelector('[data-lager-edit-status]'); if (status) { status.textContent = 'Speichern läuft …'; } try { const result = await postLagerChange({ action: 'update_lot', lotId: drawer?.dataset.lagerActiveLotId || '', manufacturerPartyId: drawer?.querySelector('[data-lager-manufacturer]')?.value || null, manufacturerLotNumber: drawer?.querySelector('[data-lager-manufacturer-lot]')?.value || '', mfgDate: drawer?.querySelector('[data-lager-mfg-date]')?.value || '', expiryDate: drawer?.querySelector('[data-lager-expiry-date]')?.value || '', purchaseDate: drawer?.querySelector('[data-lager-purchase-date]')?.value || '', receiptQty: drawer?.querySelector('[data-lager-receipt-qty]')?.value || '', adjustmentQty: drawer?.querySelector('[data-lager-adjustment-qty]')?.value || '', outQty: drawer?.querySelector('[data-lager-out-qty]')?.value || '' }); syncLagerReadView(); syncLagerBalanceView(result.balance); clearLagerMovementInputs(); setLagerEditMode(false); if (status) { status.textContent = ''; } } catch (error) { if (status) { status.textContent = error instanceof Error ? error.message : 'Speichern fehlgeschlagen'; } } });";
echo " document.addEventListener('click', (event) => { if (event.target.closest('[data-lager-detail-back]')) { event.preventDefault(); closeLagerMobileDetail(); } });";
echo " document.addEventListener('keydown', (event) => { if (event.key === 'Escape') { closeDrawer(); closeLagerMobileDetail(); } });";
echo " window.addEventListener('popstate', (event) => { if (lagerMobileDetailOpen && (!event.state || event.state.lagerView !== 'detail')) { restoreLagerMobileDetail(); } });";
echo "}";
echo "function initBestellungenBindings() {";
echo " const contentRoot = document.querySelector('[data-left-navigation-content-body]');";
echo " if (!contentRoot) { return; }";
echo " const getTable = () => contentRoot.querySelector('[data-bestellungen-large-table]');";
echo " let table = getTable();";
echo " if (!table) { return; }";
echo " let searchTimer = null;";
echo " const getSearchInput = () => {";
echo " const currentTable = getTable();";
echo " return currentTable ? currentTable.querySelector('[data-large-table-search]') : null;";
echo " };";
echo " const getSearchWrap = () => {";
echo " const input = getSearchInput();";
echo " return input ? input.closest('[data-component=\\'single-line-input\\']') : null;";
echo " };";
echo " const getSearchValue = () => {";
echo " const input = getSearchInput();";
echo " return input ? input.value.trim() : '';";
echo " };";
echo " const getSortColumn = () => {";
echo " const currentTable = getTable();";
echo " return currentTable ? (currentTable.dataset.bestellungenSortColumn || 'order_date') : 'order_date';";
echo " };";
echo " const getSortDirection = () => {";
echo " const currentTable = getTable();";
echo " return (currentTable ? (currentTable.dataset.bestellungenSortDirection || 'DESC') : 'DESC').toUpperCase();";
echo " };";
echo " const getCurrentLimit = () => {";
echo " const currentTable = getTable();";
echo " return parseInt((currentTable ? currentTable.dataset.bestellungenLimit : null) || (currentTable ? currentTable.dataset.bestellungenPageSize : null) || '20', 10);";
echo " };";
echo " const getPageSize = () => {";
echo " const currentTable = getTable();";
echo " return parseInt((currentTable ? currentTable.dataset.bestellungenPageSize : null) || '20', 10);";
echo " };";
echo " const isMobileDetailMode = () => window.matchMedia('(max-width: 767px)').matches;";
echo " const escapeHtml = (value) => String(value ?? '').replace(/[&<>\"']/g, (character) => ({ '&': '&amp;', '<': '&lt;', '>': '&gt;', '\"': '&quot;', \"'\": '&#39;' }[character] || character));";
echo " let bestellungenMobileDetailHost = null;";
echo " let bestellungenDetailOpen = false;";
echo " const syncSearchState = () => {";
echo " const input = getSearchInput();";
echo " const wrap = getSearchWrap();";
echo " if (!input || !wrap) { return; }";
echo " const hasValue = input.value.trim().length > 0;";
echo " wrap.setAttribute('data-has-value', String(hasValue));";
echo " wrap.dataset.componentState = hasValue ? 'active' : 'inactive-selectable';";
echo " };";
echo " const renderMobileDetail = (trigger) => {";
echo " const orderNumber = trigger.dataset.orderNumber || '';";
echo " const orderDate = trigger.dataset.orderDate || '';";
echo " const total = trigger.dataset.orderTotal || '';";
echo " const street = trigger.dataset.orderStreet || '';";
echo " const houseNumber = trigger.dataset.orderHouseNumber || '';";
echo " const zip = trigger.dataset.orderZip || '';";
echo " const city = trigger.dataset.orderCity || '';";
echo " const country = trigger.dataset.orderCountry || '';";
echo " const formatDate = (value) => value ? new Date(value).toLocaleString('de-CH', { dateStyle: 'short', timeStyle: 'short' }) : 'Nicht vorhanden';";
echo " const streetLine = [street, houseNumber].filter((part) => part && part.length > 0).join(' ').trim();";
echo " const cityLine = [zip, city].filter((part) => part && part.length > 0).join(' ').trim();";
echo " return [";
echo " '<div class=\"sg-bestellungen-mobile-detail-host\" data-bestellungen-mobile-detail-host=\"true\">',";
echo " '<div class=\"sg-navigation-card-layout sg-mobile-detail-back-card\">',";
echo " '<div class=\"sg-navigation-card-block\">',";
echo " '<article class=\"sg-card\" data-component=\"card\" data-pattern=\"navigation-card\" aria-label=\"Navigation Detailansicht zurück oben\">',";
echo " '<div class=\"sg-card-segment sg-card-segment--body\" data-component-part=\"card-body\" data-pattern-part=\"navigation-card-segment\">',";
echo " '<div class=\"sg-navigation-card-center\">',";
echo " '<button class=\"sg-interaction-element sg-hyperlink\" type=\"button\" data-bestellungen-detail-back>zurück</button>',";
echo " '</div>',";
echo " '</div>',";
echo " '</article>',";
echo " '</div>',";
echo " '</div>',";
echo " '<div data-bestellungen-mobile-cards><article class=\"sg-card sg-card--content-card\" data-component=\"content-card\" aria-label=\"Bestell-Details\">',";
echo " '<div class=\"sg-card-segment sg-card-segment--body sg-vsf-drawer-card__content\">',";
echo " '<p class=\"sg-body\"><strong>Bestellnummer:</strong> <span>' + escapeHtml(orderNumber) + '</span></p>',";
echo " '<p class=\"sg-body\"><strong>Bestelldatum:</strong> <span>' + escapeHtml(orderDate) + '</span></p>',";
echo " '<p class=\"sg-body\"><strong>Lieferadresse:</strong></p>',";
echo " '<p class=\"sg-body\">' + escapeHtml(streetLine) + '</p>',";
echo " '<p class=\"sg-body\">' + escapeHtml(cityLine) + '</p>',";
echo " '<p class=\"sg-body\">' + escapeHtml(country) + '</p>',";
echo " '<p class=\"sg-body\"><strong>Gesamtsumme:</strong> <span>' + escapeHtml(total) + '</span></p>',";
echo " '<p class=\"sg-body\">Detailinhalt wird noch definiert.</p>',";
echo " '</div>',";
echo " '</article></div>',";
echo " '</div>'";
echo " ].join('');";
echo " };";
echo " const getDrawer = () => contentRoot.querySelector('[data-bestellungen-drawer]');";
echo " const getDrawerBackdrop = () => contentRoot.querySelector('[data-bestellungen-drawer-backdrop]');";
echo " const setDrawerState = (open) => {";
echo " const drawer = getDrawer();";
echo " const backdrop = getDrawerBackdrop();";
echo " if (!drawer || !backdrop) { return; }";
echo " drawer.dataset.open = String(open);";
echo " drawer.setAttribute('aria-hidden', String(!open));";
echo " backdrop.dataset.open = String(open);";
echo " backdrop.setAttribute('aria-hidden', String(!open));";
echo " document.body.classList.toggle('sg-card-list-page-drawer-open', open);";
echo " };";
echo " const closeDrawer = () => {";
echo " setDrawerState(false);";
echo " contentRoot.querySelectorAll('[data-order-drawer-open]').forEach((trigger) => {";
echo " trigger.setAttribute('aria-expanded', 'false');";
echo " });";
echo " };";
echo " const openDrawer = (trigger) => {";
echo " const drawer = getDrawer();";
echo " if (!drawer) { return; }";
echo " if (isMobileDetailMode()) {";
echo " openMobileDetail(trigger);";
echo " return;";
echo " }";
echo " const drawerTitle = drawer.querySelector('[data-order-drawer-title]');";
echo " const cards = drawer.querySelector('[data-order-drawer-cards]');";
echo " const orderId = trigger.dataset.orderId || '';";
echo " const formatAmount = (value, currency) => value === null || value === undefined ? 'Nicht vorhanden' : currency + ' ' + Number(value).toFixed(2);";
echo " const formatDate = (value) => value ? new Date(value).toLocaleString('de-CH', { dateStyle: 'short', timeStyle: 'short' }) : 'Nicht vorhanden';";
echo " const value = (label, content) => '<p class=\"sg-body\"><strong>' + escapeHtml(label) + ':</strong> ' + escapeHtml(content || 'Nicht vorhanden') + '</p>';";
echo " const renderCards = (order) => {";
echo " const c = order.customer || {}; const a = order.amounts || {}; const address = [[c.street, c.house_number].filter(Boolean).join(' '), [c.zip, c.city].filter(Boolean).join(' '), c.country_name].filter(Boolean).join('<br>');";
echo " const lines = (order.lines || []).map((line) => '<div class=\"sg-card-segment sg-card-segment--body\"><p class=\"sg-body\"><strong>' + escapeHtml(line.item_name) + '</strong> · ' + escapeHtml(line.item_code) + ' · Menge: ' + escapeHtml(String(line.qty)) + '</p>' + value('Positionsstatus', line.line_status) + value('Einzelpreis', formatAmount(line.unit_price, a.currency || 'CHF')) + value('Positionssumme', formatAmount(line.line_total, a.currency || 'CHF')) + '</div>').join('');";
echo " const allocations = (order.lines || []).flatMap((line) => (line.product_allocations || []).map((item) => '<div class=\"sg-body\"><strong>' + escapeHtml(item.product_name) + ':</strong> ' + escapeHtml(item.lot_number || 'Nicht zugeordnet') + ' · ' + escapeHtml(item.allocated_qty === null ? 'Nicht zugeordnet' : String(item.allocated_qty)) + ' · ' + escapeHtml(item.allocation_status || 'Nicht vorhanden') + (item.lot_status === 'virtual_shortage' ? ' · Virtuelle Fehlbestandscharge' : '') + '</div>')).join('');";
echo " return '<article class=\"sg-card sg-card--content-card\" data-component=\"content-card\" aria-label=\"Bestellübersicht\"><header class=\"sg-card-segment sg-card-segment--header sg-card-segment--darkgreen\" data-component-part=\"card-header\"><div class=\"sg-strong sg-text-on-dark\">Bestellübersicht</div></header><div class=\"sg-card-segment sg-card-segment--body\" data-component-part=\"card-body\">' + value('Bestellnummer', order.external_ref) + value('Bestelldatum', formatDate(order.order_date)) + value('Verkaufskanal', order.order_source) + value('Bestellstatus', order.order_status) + value('Zahlungsstatus', order.payment_status) + value('Zahlungsart', order.payment_method) + value('Versandart', order.shipping_method) + '<p class=\"sg-body\"><strong>Kunde:</strong> ' + escapeHtml([c.first_name, c.last_name].filter(Boolean).join(' ') || 'Nicht vorhanden') + '</p><p class=\"sg-body\"><strong>Lieferadresse:</strong><br>' + address + '</p>' + value('Netto', formatAmount(a.net, a.currency || 'CHF')) + value('Versand', formatAmount(a.shipping, a.currency || 'CHF')) + value('Rabatt', formatAmount(a.discount, a.currency || 'CHF')) + value('Steuer', formatAmount(a.tax, a.currency || 'CHF')) + value('Gesamtsumme', formatAmount(a.total, a.currency || 'CHF')) + '</div></article><article class=\"sg-card sg-card--content-card\" data-component=\"content-card\" aria-label=\"Bestellte Artikel\"><header class=\"sg-card-segment sg-card-segment--header sg-card-segment--darkgreen\" data-component-part=\"card-header\"><div class=\"sg-strong sg-text-on-dark\">Bestellte Artikel</div></header>' + (lines || '<div class=\"sg-card-segment sg-card-segment--body\" data-component-part=\"card-body\"><p class=\"sg-body\">Keine Artikel vorhanden.</p></div>') + '</article><article class=\"sg-card sg-card--content-card\" data-component=\"content-card\" aria-label=\"Chargenzuordnung\"><header class=\"sg-card-segment sg-card-segment--header sg-card-segment--darkgreen\" data-component-part=\"card-header\"><div class=\"sg-strong sg-text-on-dark\">Chargenzuordnung</div></header><div class=\"sg-card-segment sg-card-segment--body\" data-component-part=\"card-body\">' + (allocations || '<p class=\"sg-body\">Keine Chargenzuordnung vorhanden.</p>') + '</div></article>';";
echo " };";
echo " setDrawerState(true);";
echo " if (drawerTitle) { drawerTitle.textContent = trigger.dataset.orderNumber ? 'Bestellung ' + trigger.dataset.orderNumber : 'Bestellung'; }";
echo " if (cards) { cards.innerHTML = '<p class=\"sg-body\">Bestelldetails werden geladen …</p>'; }";
echo " fetch('/api/bestellungen/detail.php?id=' + encodeURIComponent(orderId), { credentials: 'same-origin' }).then((response) => response.ok ? response.json() : Promise.reject(new Error('Bestelldetails konnten nicht geladen werden.'))).then((payload) => { if (!payload.ok) { throw new Error('Bestelldetails konnten nicht geladen werden.'); } if (cards) { cards.innerHTML = renderCards(payload.order); } }).catch((error) => { if (cards) { cards.innerHTML = '<p class=\"sg-body\">' + escapeHtml(error.message) + '</p>'; } });";
echo " contentRoot.querySelectorAll('[data-order-drawer-open]').forEach((button) => {";
echo " button.setAttribute('aria-expanded', String(button === trigger));";
echo " });";
echo " };";
echo " const restoreBestellungenList = () => {";
echo " if (bestellungenMobileDetailHost && bestellungenMobileDetailHost.parentNode) {";
echo " bestellungenMobileDetailHost.parentNode.removeChild(bestellungenMobileDetailHost);";
echo " }";
echo " bestellungenMobileDetailHost = null;";
echo " document.body.classList.remove('sg-bestellungen-mobile-detail-open');";
echo " bestellungenDetailOpen = false;";
echo " bindTable();";
echo " };";
echo " const openMobileDetail = (trigger) => {";
echo " restoreBestellungenList();";
echo " const host = document.createElement('div');";
echo " host.innerHTML = renderMobileDetail(trigger);";
echo " bestellungenMobileDetailHost = host.firstElementChild;";
echo " if (bestellungenMobileDetailHost) {";
echo " document.body.appendChild(bestellungenMobileDetailHost);";
echo " document.body.classList.add('sg-bestellungen-mobile-detail-open');";
echo " }";
echo " fetch('/api/bestellungen/detail.php?id=' + encodeURIComponent(trigger.dataset.orderId || ''), { credentials: 'same-origin' }).then((response) => response.ok ? response.json() : Promise.reject(new Error('Bestelldetails konnten nicht geladen werden.'))).then((payload) => { if (!payload.ok || !bestellungenMobileDetailHost) { throw new Error('Bestelldetails konnten nicht geladen werden.'); } const order = payload.order; const cards = bestellungenMobileDetailHost.querySelector('[data-bestellungen-mobile-cards]'); const lines = (order.lines || []).map((line) => '<p class=\"sg-body\"><strong>' + escapeHtml(line.item_name) + '</strong> · ' + escapeHtml(line.item_code) + ' · Menge: ' + escapeHtml(String(line.qty)) + ' · Status: ' + escapeHtml(line.line_status) + '</p>').join(''); const allocations = (order.lines || []).flatMap((line) => (line.product_allocations || []).map((item) => '<p class=\"sg-body\"><strong>' + escapeHtml(item.product_name) + ':</strong> ' + escapeHtml(item.lot_number || 'Nicht zugeordnet') + ' · ' + escapeHtml(item.allocation_status || 'Nicht vorhanden') + '</p>')).join(''); if (cards) { cards.innerHTML = '<article class=\"sg-card sg-card--content-card\"><header class=\"sg-card-segment sg-card-segment--header sg-card-segment--darkgreen\"><div class=\"sg-strong sg-text-on-dark\">Bestellübersicht</div></header><div class=\"sg-card-segment sg-card-segment--body\"><p class=\"sg-body\"><strong>Bestellnummer:</strong> ' + escapeHtml(order.external_ref) + '</p><p class=\"sg-body\"><strong>Bestelldatum:</strong> ' + escapeHtml(formatDate(order.order_date)) + '</p><p class=\"sg-body\"><strong>Verkaufskanal:</strong> ' + escapeHtml(order.order_source) + '</p><p class=\"sg-body\"><strong>Status:</strong> ' + escapeHtml(order.order_status) + '</p></div></article><article class=\"sg-card sg-card--content-card\"><header class=\"sg-card-segment sg-card-segment--header sg-card-segment--darkgreen\"><div class=\"sg-strong sg-text-on-dark\">Bestellte Artikel</div></header><div class=\"sg-card-segment sg-card-segment--body\">' + (lines || '<p class=\"sg-body\">Keine Artikel vorhanden.</p>') + '</div></article><article class=\"sg-card sg-card--content-card\"><header class=\"sg-card-segment sg-card-segment--header sg-card-segment--darkgreen\"><div class=\"sg-strong sg-text-on-dark\">Chargenzuordnung</div></header><div class=\"sg-card-segment sg-card-segment--body\">' + (allocations || '<p class=\"sg-body\">Keine Chargenzuordnung vorhanden.</p>') + '</div></article>'; } }).catch((error) => { const cards = bestellungenMobileDetailHost?.querySelector('[data-bestellungen-mobile-cards]'); if (cards) { cards.innerHTML = '<p class=\"sg-body\">' + escapeHtml(error.message) + '</p>'; } });";
echo " bestellungenDetailOpen = true;";
echo " window.history.pushState({ bestellungenView: 'detail', orderId: trigger.dataset.orderId || '' }, '', window.location.href);";
echo " };";
echo " const closeMobileDetail = () => {";
echo " if (!bestellungenDetailOpen) { return; }";
echo " if (window.history.state && window.history.state.bestellungenView === 'detail') {";
echo " window.history.back();";
echo " return;";
echo " }";
echo " restoreBestellungenList();";
echo " };";
echo " const buildUrl = (params) => {";
echo " const url = new URL(window.location.href);";
echo " url.hash = '';";
echo " Object.entries(params).forEach(([key, value]) => {";
echo " if (value === null || value === undefined || value === '') {";
echo " url.searchParams.delete(key);";
echo " return;";
echo " }";
echo " url.searchParams.set(key, String(value));";
echo " });";
echo " return url;";
echo " };";
echo " const buildFragmentUrl = (params) => {";
echo " const url = buildUrl(params);";
echo " return url;";
echo " };";
echo " const replaceFragment = (html) => {";
echo " const doc = new DOMParser().parseFromString(html, 'text/html');";
echo " const fragment = doc.querySelector('[data-bestellungen-content]');";
echo " if (!fragment) {";
echo " return false;";
echo " }";
echo " contentRoot.innerHTML = fragment.innerHTML;";
echo " if (bestellungenMobileDetailHost && bestellungenMobileDetailHost.parentNode) {";
echo " bestellungenMobileDetailHost.parentNode.removeChild(bestellungenMobileDetailHost);";
echo " }";
echo " bestellungenMobileDetailHost = null;";
echo " document.body.classList.remove('sg-bestellungen-mobile-detail-open');";
echo " bestellungenDetailOpen = false;";
echo " table = getTable();";
echo " return !!table;";
echo " };";
echo " const focusSearchInput = () => {";
echo " const input = getSearchInput();";
echo " if (!input) { return; }";
echo " input.focus({ preventScroll: true });";
echo " const end = input.value.length;";
echo " try {";
echo " input.setSelectionRange(end, end);";
echo " } catch (error) {";
echo " void error;";
echo " }";
echo " };";
echo " const loadFragment = async (params) => {";
echo " if (searchTimer) { window.clearTimeout(searchTimer); searchTimer = null; }";
echo " const wasSearchFocused = getSearchInput() ? document.activeElement === getSearchInput() : false;";
echo " const url = buildFragmentUrl(params);";
echo " const response = await fetch(url.toString(), { credentials: 'same-origin', headers: { 'X-Requested-With': 'XMLHttpRequest' } });";
echo " const html = await response.text();";
echo " const replaced = replaceFragment(html);";
echo " if (replaced) {";
echo " const historyUrl = buildUrl(params);";
echo " window.history.replaceState({}, '', historyUrl);";
echo " bindTable();";
echo " if (wasSearchFocused) { focusSearchInput(); }";
echo " }";
echo " };";
echo " const bindTable = () => {";
echo " table = getTable();";
echo " if (!table) { return; }";
echo " const searchInput = getSearchInput();";
echo " const clearButton = table.querySelector('[data-bestellungen-search-clear]');";
echo " if (searchInput && searchInput.dataset.bestellungenBound !== 'true') {";
echo " searchInput.dataset.bestellungenBound = 'true';";
echo " searchInput.addEventListener('input', () => {";
echo " syncSearchState();";
echo " if (searchTimer) { window.clearTimeout(searchTimer); }";
echo " searchTimer = window.setTimeout(() => {";
echo " void loadFragment({";
echo " bestellungen_search: getSearchValue(),";
echo " bestellungen_sort: getSortColumn(),";
echo " bestellungen_dir: getSortDirection(),";
echo " bestellungen_limit: getPageSize(),";
echo " });";
echo " }, 500);";
echo " });";
echo " }";
echo " if (clearButton && clearButton.dataset.bestellungenBound !== 'true') {";
echo " clearButton.dataset.bestellungenBound = 'true';";
echo " clearButton.addEventListener('click', () => {";
echo " if (searchTimer) { window.clearTimeout(searchTimer); searchTimer = null; }";
echo " const input = getSearchInput();";
echo " if (input) { input.value = ''; }";
echo " syncSearchState();";
echo " void loadFragment({";
echo " bestellungen_search: '',";
echo " bestellungen_sort: getSortColumn(),";
echo " bestellungen_dir: getSortDirection(),";
echo " bestellungen_limit: getPageSize(),";
echo " });";
echo " });";
echo " }";
echo " syncSearchState();";
echo " };";
echo " const getCurrentQueryParams = () => ({";
echo " bestellungen_search: getSearchValue(),";
echo " bestellungen_sort: getSortColumn(),";
echo " bestellungen_dir: getSortDirection(),";
echo " bestellungen_limit: getCurrentLimit(),";
echo " });";
echo " const getOpenDrawerOrderId = () => {";
echo " const trigger = Array.from(contentRoot.querySelectorAll('[data-order-drawer-open]')).find((button) => button.getAttribute('aria-expanded') === 'true');";
echo " return trigger ? (trigger.dataset.orderId || '') : '';";
echo " };";
echo " const reloadBestellungenSection = () => loadFragment(getCurrentQueryParams());";
echo " const reloadBestellungenRow = async (orderId) => {";
echo " const targetOrderId = String(orderId || '');";
echo " if (targetOrderId === '') {";
echo " await reloadBestellungenSection();";
echo " return;";
echo " }";
echo " const response = await fetch(buildFragmentUrl(getCurrentQueryParams()).toString(), { credentials: 'same-origin', headers: { 'X-Requested-With': 'XMLHttpRequest' } });";
echo " if (!response.ok) {";
echo " await reloadBestellungenSection();";
echo " return;";
echo " }";
echo " const html = await response.text();";
echo " const doc = new DOMParser().parseFromString(html, 'text/html');";
echo " const newRow = Array.from(doc.querySelectorAll('[data-bestellungen-row]')).find((row) => (row.dataset.orderId || '') === targetOrderId) || null;";
echo " const currentRow = Array.from(contentRoot.querySelectorAll('[data-bestellungen-row]')).find((row) => (row.dataset.orderId || '') === targetOrderId) || null;";
echo " if (!newRow || !currentRow) {";
echo " await reloadBestellungenSection();";
echo " return;";
echo " }";
echo " const openDrawerOrderId = getOpenDrawerOrderId();";
echo " currentRow.outerHTML = newRow.outerHTML;";
echo " if (openDrawerOrderId === targetOrderId) {";
echo " const reopenedTrigger = Array.from(contentRoot.querySelectorAll('[data-order-drawer-open]')).find((button) => (button.dataset.orderId || '') === targetOrderId) || null;";
echo " if (reopenedTrigger) {";
echo " openDrawer(reopenedTrigger);";
echo " }";
echo " }";
echo " };";
echo " if (!bestellungenTableHandlersInstalled) {";
echo " bestellungenTableHandlersInstalled = true;";
echo " document.addEventListener('click', (event) => {";
echo " const detailBackTrigger = event.target.closest('[data-bestellungen-detail-back]');";
echo " if (detailBackTrigger) {";
echo " event.preventDefault();";
echo " closeMobileDetail();";
echo " }";
echo " });";
echo " contentRoot.addEventListener('click', (event) => {";
echo " const openTrigger = event.target.closest('[data-order-drawer-open]');";
echo " if (openTrigger) {";
echo " event.preventDefault();";
echo " openDrawer(openTrigger);";
echo " return;";
echo " }";
echo " const closeTrigger = event.target.closest('[data-order-drawer-close]');";
echo " if (closeTrigger) {";
echo " event.preventDefault();";
echo " closeDrawer();";
echo " return;";
echo " }";
echo " const backdrop = event.target.closest('[data-bestellungen-drawer-backdrop]');";
echo " if (backdrop) {";
echo " event.preventDefault();";
echo " closeDrawer();";
echo " return;";
echo " }";
echo " const sortButton = event.target.closest('[data-bestellungen-sort-button]');";
echo " if (sortButton) {";
echo " event.preventDefault();";
echo " void loadFragment({";
echo " bestellungen_search: getSearchValue(),";
echo " bestellungen_sort: sortButton.dataset.bestellungenSortColumn || getSortColumn(),";
echo " bestellungen_dir: sortButton.dataset.bestellungenSortDirection || getSortDirection(),";
echo " bestellungen_limit: getPageSize(),";
echo " });";
echo " return;";
echo " }";
echo " const loadMoreTrigger = event.target.closest('[data-large-table-load-more-trigger]');";
echo " if (loadMoreTrigger) {";
echo " event.preventDefault();";
echo " void loadFragment({";
echo " bestellungen_search: getSearchValue(),";
echo " bestellungen_sort: getSortColumn(),";
echo " bestellungen_dir: getSortDirection(),";
echo " bestellungen_limit: getCurrentLimit() + getPageSize(),";
echo " });";
echo " }";
echo " });";
echo " document.addEventListener('keydown', (event) => {";
echo " if (event.key === 'Escape') {";
echo " closeDrawer();";
echo " }";
echo " });";
echo " window.addEventListener('popstate', (event) => {";
echo " if (bestellungenDetailOpen && (!event.state || event.state.bestellungenView !== 'detail')) {";
echo " restoreBestellungenList();";
echo " }";
echo " });";
echo " if (!window.history.state || window.history.state.bestellungenView !== 'list') {";
echo " window.history.replaceState({ bestellungenView: 'list' }, '', window.location.href);";
echo " }";
echo " }";
echo " bindTable();";
echo "}";
echo "(() => {";
echo " const overlay = document.querySelector('[data-otc-order-overlay]');";
echo " if (!overlay) { return; }";
echo " const form = overlay.querySelector('[data-otc-order-form]');";
echo " const productInputs = Array.from(form.querySelectorAll('[data-otc-order-product]'));";
echo " const orderDateInput = form.querySelector('[data-otc-order-date]');";
echo " const orderDateDefaultValue = orderDateInput ? orderDateInput.value : '';";
echo " const paymentRows = form.querySelector('[data-otc-payment-rows]');";
echo " const addPaymentButton = form.querySelector('[data-otc-payment-add]');";
echo " const paymentOptionValues = ['twint', 'card', 'cash', 'paypal', 'bank_transfer'];";
echo " const paymentOptionLabels = { twint: 'Twint', card: 'Kreditkarte', cash: 'Barzahlung', paypal: 'PayPal', bank_transfer: 'Überweisung' };";
echo " const firstNameInput = form.querySelector('[data-otc-order-first-name]');";
echo " const lastNameInput = form.querySelector('[data-otc-order-last-name]');";
echo " const streetInput = form.querySelector('[data-otc-order-street]');";
echo " const houseNumberInput = form.querySelector('[data-otc-order-house-number]');";
echo " const zipInput = form.querySelector('[data-otc-order-zip]');";
echo " const cityInput = form.querySelector('[data-otc-order-city]');";
echo " const submitBtn = overlay.querySelector('[data-otc-order-submit]');";
echo " const errorEl = form.querySelector('[data-otc-order-error]');";
echo " const successEl = form.querySelector('[data-otc-order-success]');";
echo " const successDefaultText = successEl ? successEl.textContent : '';";
echo " const confirmationStage = overlay.querySelector('[data-otc-confirmation-stage]');";
echo " const confirmationCard = overlay.querySelector('[data-otc-confirmation-card]');";
echo " const confirmationProducts = overlay.querySelector('[data-otc-confirmation-products]');";
echo " const confirmationQuantity = overlay.querySelector('[data-otc-confirmation-quantity]');";
echo " const confirmationTotal = overlay.querySelector('[data-otc-confirmation-total]');";
echo " const confirmationSubmit = overlay.querySelector('[data-otc-confirmation-submit]');";
echo " let pendingOrderData = null;";
echo " const openTriggers = () => document.querySelectorAll('[data-otc-order-open]');";
echo " const setTriggerState = (expanded) => {";
echo " openTriggers().forEach((trigger) => { trigger.setAttribute('aria-expanded', String(expanded)); });";
echo " };";
echo " const clearError = () => {";
echo " if (errorEl) { errorEl.textContent = ''; errorEl.classList.add('hidden'); }";
echo " };";
echo " const clearSuccess = () => {";
echo " if (successEl) { successEl.textContent = successDefaultText; successEl.classList.add('hidden'); }";
echo " };";
echo " const getTodayValue = () => {";
echo " const now = new Date();";
echo " const year = now.getFullYear();";
echo " const month = String(now.getMonth() + 1).padStart(2, '0');";
echo " const day = String(now.getDate()).padStart(2, '0');";
echo " return year + '-' + month + '-' + day;";
echo " };";
echo " const ensureCurrentOrderDate = () => {";
echo " if (!orderDateInput) { return; }";
echo " if (!orderDateInput.value || orderDateInput.value === orderDateDefaultValue) {";
echo " orderDateInput.value = getTodayValue();";
echo " }";
echo " };";
echo " const toggleOverlay = (isOpen) => {";
echo " overlay.dataset.open = String(isOpen);";
echo " overlay.setAttribute('aria-hidden', String(!isOpen));";
echo " document.body.classList.toggle('sg-otc-order-overlay-open', isOpen);";
echo " setTriggerState(isOpen);";
echo " if (isOpen) {";
echo " clearError();";
echo " clearSuccess();";
echo " ensureCurrentOrderDate();";
echo " requestAnimationFrame(() => {";
echo " (productInputs[0] || submitBtn)?.focus();";
echo " });";
echo " return;";
echo " }";
echo " clearError();";
echo " clearSuccess();";
echo " };";
echo " const getInputValue = (input) => parseInt(input.value || '0', 10) || 0;";
echo " const getFieldValue = (input) => (input ? input.value.trim() : '');";
echo " const updatePaymentAddButton = () => { addPaymentButton.disabled = paymentRows.querySelectorAll('[data-otc-payment-row]').length >= paymentOptionValues.length; };";
echo " const updateFormState = () => {";
echo " const totalQty = productInputs.reduce((sum, input) => sum + getInputValue(input), 0);";
echo " const isValid = totalQty > 0";
echo " && !!getFieldValue(orderDateInput)";
echo " && paymentRows.querySelectorAll('[data-otc-payment-row]').length > 0";
echo " && !!getFieldValue(firstNameInput)";
echo " && !!getFieldValue(lastNameInput)";
echo " && !!getFieldValue(streetInput)";
echo " && !!getFieldValue(houseNumberInput)";
echo " && !!getFieldValue(zipInput)";
echo " && !!getFieldValue(cityInput);";
echo " let errorMsg = '';";
echo " if (totalQty === 0) {";
echo " errorMsg = 'Mindestens ein Produkt mit Menge > 0 erforderlich.';";
echo " } else if (!getFieldValue(orderDateInput)) {";
echo " errorMsg = 'Bestelldatum auswählen.';";
echo " } else if (!getFieldValue(firstNameInput) || !getFieldValue(lastNameInput) || !getFieldValue(streetInput) || !getFieldValue(houseNumberInput) || !getFieldValue(zipInput) || !getFieldValue(cityInput)) {";
echo " errorMsg = 'Alle Rechnungsadress-Felder ausfüllen.';";
echo " }";
echo " if (errorEl) {";
echo " errorEl.textContent = errorMsg;";
echo " errorEl.classList.toggle('hidden', errorMsg === '');";
echo " }";
echo " submitBtn.disabled = !isValid;";
echo " submitBtn.setAttribute('aria-disabled', String(!isValid));";
echo " submitBtn.classList.toggle('sg-button--process-inactive', !isValid);";
echo " return isValid;";
echo " };";
echo " const resetForm = (preserveSuccess = false) => {";
echo " form.reset();";
echo " Array.from(paymentRows.querySelectorAll('[data-otc-payment-row]')).slice(1).forEach((row) => row.remove());";
echo " updatePaymentAddButton();";
echo " clearError();";
echo " if (!preserveSuccess) { clearSuccess(); }";
echo " if (!preserveSuccess) { updateFormState(); }";
echo " };";
echo " const closeConfirmation = () => {";
echo " pendingOrderData = null;";
echo " confirmationStage.dataset.dialogOpen = 'false';";
echo " confirmationCard.hidden = true;";
echo " };";
echo " const openConfirmation = (orderData) => {";
echo " pendingOrderData = orderData;";
echo " confirmationProducts.replaceChildren();";
echo " orderData.products.forEach((product) => {";
echo " const input = productInputs.find((candidate) => parseInt(candidate.dataset.productId || '0', 10) === product.productId);";
echo " const item = document.createElement('div');";
echo " item.className = 'sg-body';";
echo " item.textContent = (input?.dataset.title || 'Produkt') + ': ' + product.qty;";
echo " confirmationProducts.appendChild(item);";
echo " });";
echo " confirmationQuantity.textContent = String(orderData.products.reduce((sum, product) => sum + product.qty, 0));";
echo " confirmationTotal.textContent = orderData.payments.reduce((sum, payment) => sum + payment.amount, 0).toFixed(2);";
echo " confirmationStage.dataset.dialogOpen = 'true';";
echo " confirmationCard.hidden = false;";
echo " requestAnimationFrame(() => confirmationSubmit.focus());";
echo " };";
echo " document.addEventListener('click', (event) => {";
echo " const openTrigger = event.target.closest('[data-otc-order-open]');";
echo " if (openTrigger) {";
echo " event.preventDefault();";
echo " toggleOverlay(true);";
echo " return;";
echo " }";
echo " const closeTrigger = event.target.closest('[data-otc-order-close]');";
echo " if (closeTrigger) {";
echo " event.preventDefault();";
echo " toggleOverlay(false);";
echo " }";
echo " });";
echo " [orderDateInput, firstNameInput, lastNameInput, streetInput, houseNumberInput, zipInput, cityInput].forEach((input) => {";
echo " if (!input) { return; }";
echo " input.addEventListener('input', updateFormState);";
echo " input.addEventListener('change', updateFormState);";
echo " });";
echo " productInputs.forEach((input) => {";
echo " input.addEventListener('input', updateFormState);";
echo " input.addEventListener('change', updateFormState);";
echo " });";
echo " const bindPaymentRow = (row) => {";
echo " row.querySelectorAll('select, input').forEach((input) => { input.addEventListener('input', updateFormState); input.addEventListener('change', updateFormState); });";
echo " };";
echo " const paymentOptions = paymentOptionValues.map((value) => '<option value=\"' + value + '\">' + paymentOptionLabels[value] + '</option>').join('');";
echo " const addPaymentRow = () => {";
echo " const number = paymentRows.querySelectorAll('[data-otc-payment-row]').length + 1;";
echo " if (number > paymentOptionValues.length) { updatePaymentAddButton(); return; }";
echo " const nextPaymentMethod = paymentOptionValues[number - 1];";
echo " const row = document.createElement('div');";
echo " row.className = 'sg-form-sections-card__field-group';";
echo " row.dataset.otcPaymentRow = '';";
echo " row.innerHTML = '<label class=\"sg-labeled-input-row\"><span class=\"sg-label\">Bezahlart</span><select class=\"sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable sg-pulldown\" id=\"otc-payment-method-' + number + '\" data-otc-payment-method>' + paymentOptions + '</select></label><label class=\"sg-labeled-input-row\"><span class=\"sg-label\">Betrag (CHF)</span><input class=\"sg-interaction-element sg-input-single-line sg-input-single-line--inactive-selectable sg-form-inactive-selectable\" type=\"number\" id=\"otc-payment-amount-' + number + '\" min=\"0.01\" step=\"0.01\" value=\"0.00\" data-otc-payment-amount></label>' ;";
echo " row.querySelector('[data-otc-payment-method]').value = nextPaymentMethod;";
echo " paymentRows.appendChild(row);";
echo " bindPaymentRow(row);";
echo " updatePaymentAddButton();";
echo " updateFormState();";
echo " };";
echo " addPaymentButton.addEventListener('click', addPaymentRow);";
echo " bindPaymentRow(paymentRows.querySelector('[data-otc-payment-row]'));";
echo " updatePaymentAddButton();";
echo " const submitOrder = async (orderData) => {";
echo " let submissionSucceeded = false;";
echo " const originalBtnText = confirmationSubmit.innerHTML;";
echo " confirmationSubmit.innerHTML = '<span class=\"loading\"></span> Wird verarbeitet...';";
echo " confirmationSubmit.disabled = true;";
echo " clearError();";
echo " try {";
echo " const response = await fetch('/api/otc-order.php', {";
echo " method: 'POST',";
echo " headers: { 'Content-Type': 'application/json' },";
echo " body: JSON.stringify(orderData)";
echo " });";
echo " const result = await response.json();";
echo " if (response.ok && result.ok) {";
echo " submissionSucceeded = true;";
echo " if (successEl) {";
echo " successEl.textContent = result.externalRef ? 'Bestellung erfolgreich erfasst! Bestellnummer: ' + result.externalRef : successDefaultText;";
echo " successEl.classList.remove('hidden');";
echo " }";
echo " closeConfirmation();";
echo " resetForm();";
echo " toggleOverlay(false);";
echo " } else if (errorEl) {";
echo " errorEl.textContent = result.error || 'Unbekannter Fehler';";
echo " errorEl.classList.remove('hidden');";
echo " closeConfirmation();";
echo " }";
echo " } catch (error) {";
echo " if (errorEl) {";
echo " errorEl.textContent = 'Netzwerkfehler: ' + error.message;";
echo " errorEl.classList.remove('hidden');";
echo " }";
echo " closeConfirmation();";
echo " } finally {";
echo " confirmationSubmit.innerHTML = originalBtnText;";
echo " confirmationSubmit.disabled = false;";
echo " if (!submissionSucceeded) { updateFormState(); }";
echo " }";
echo " };";
echo " form.addEventListener('submit', (event) => {";
echo " event.preventDefault();";
echo " if (!updateFormState()) { return; }";
echo " const products = productInputs";
echo " .filter((input) => getInputValue(input) > 0)";
echo " .map((input) => ({ productId: parseInt(input.dataset.productId || '0', 10), qty: getInputValue(input) }));";
echo " const orderData = {";
echo " products: products,";
echo " orderDate: orderDateInput ? orderDateInput.value : '',";
echo " payments: Array.from(paymentRows.querySelectorAll('[data-otc-payment-row]')).map((row) => ({ paymentMethod: row.querySelector('[data-otc-payment-method]').value, amount: parseFloat(row.querySelector('[data-otc-payment-amount]').value || '0') || 0 })),";
echo " billing: {";
echo " firstName: getFieldValue(firstNameInput),";
echo " lastName: getFieldValue(lastNameInput),";
echo " street: getFieldValue(streetInput),";
echo " houseNumber: getFieldValue(houseNumberInput),";
echo " zip: getFieldValue(zipInput),";
echo " city: getFieldValue(cityInput)";
echo " }";
echo " };";
echo " openConfirmation(orderData);";
echo " });";
echo " confirmationStage.addEventListener('click', (event) => {";
echo " if (event.target.closest('[data-otc-confirmation-cancel]')) { closeConfirmation(); return; }";
echo " if (event.target.closest('[data-otc-confirmation-submit]') && pendingOrderData) { submitOrder(pendingOrderData); }";
echo " });";
echo " updateFormState();";
echo "})();";
echo "if (window.sgInitHelpIconOverlays) {";
echo " window.sgInitHelpIconOverlays({";
echo " closeOnOpenSelectors: ['.sg-sandwich-menu-wrap'],";
echo " outsideClickIgnoreSelectors: ['.sg-sandwich-menu-wrap'],";
echo " });";
echo "}";
echo "renderMainHeading('ERP');";
echo "renderLeftNavigation('ERP');";
echo '</script>';
echo '</body>';
echo '</html>';
}