$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[] = '';
$html[] = '';
$html[] = '';
$html[] = '';
$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[] = '';
$headerIndex++;
}
$html[] = '
';
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[] = '';
$html[] = '
' . auth_escape_html($orderDate) . '
';
$html[] = '
';
$html[] = '
';
$html[] = '
' . auth_escape_html($totalAmount) . '
';
$html[] = '
';
}
if ($hasMore) {
$loadMoreUrl = auth_build_path_with_query([
'bestellungen_search' => $search !== '' ? $search : null,
'bestellungen_sort' => $sortColumn,
'bestellungen_dir' => $sortDirection,
'bestellungen_limit' => $nextLimit,
]);
$html[] = '';
$html[] = '
';
$html[] = '
';
$html[] = '
';
$html[] = '
';
$html[] = '';
$html[] = '
';
$html[] = '
';
$html[] = '';
$html[] = '
';
$html[] = '
';
$html[] = '
';
$html[] = '
';
}
$html[] = '';
$html[] = '';
$html[] = '
';
$html[] = '';
return implode('', $html);
}
function auth_render_bestellungen_content(array $bestellungenTable): string
{
return ''
. '
'
. auth_render_bestellungen_large_table($bestellungenTable)
. '
';
}
function auth_render_lager_table(string $title, array $rows, array $columns, string $tableKey): string
{
$html = [];
$html[] = '';
$html[] = '';
$html[] = '';
foreach ($columns as $label) {
$html[] = '';
}
$html[] = '
';
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['current_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-documents="' . auth_escape_html((string) json_encode($row['documents'] ?? [], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES)) . '"'
. ' 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[] = '';
$html[] = '
';
$html[] = '
';
if ($tableKey === 'products') {
$forecastClass = $forecastWarning
? ' sg-strong lager-forecast-warning'
: ($forecastMhdWarning ? ' sg-strong lager-forecast-mhd-warning' : '');
$html[] = '
' . auth_escape_html($forecastText) . '
';
}
$html[] = '
';
}
$html[] = '';
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_documents(array $documents, bool $editable, string $scope): string
{
$segmentClass = $editable ? ' sg-card-segment--gray' : '';
$segmentState = $editable ? ' hidden data-lager-edit-documents="' . auth_escape_html($scope) . '"' : '';
$html = '';
if ($editable) {
$html .= '
' : '');
}
function auth_render_lager_historical_lots(array $lagerProducts): string
{
$html = [];
foreach ($lagerProducts as $product) {
$productId = (int) ($product['id'] ?? 0);
$html[] = '';
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[] = '
'
. ''
. ''
. '
Naurua-Chargennummer: ' . auth_escape_html((string) ($lot['lot_number'] ?? 'Nicht hinterlegt')) . '
'
. 'Status: Abgeschlossen
'
. 'Eingangsmenge: ' . auth_format_lager_quantity((float) ($lot['qty_in'] ?? 0)) . '
'
. 'Verbrauchte Menge: ' . auth_format_lager_quantity((float) ($lot['qty_out'] ?? 0)) . '
'
. 'Verbrauchszeitraum: ' . auth_format_lager_date($lot['first_in_at'] ?? null) . ' – ' . auth_format_lager_date($lot['last_out_at'] ?? null) . '
'
. 'Aufgebraucht am: ' . $emptyDate . '
'
. 'MHD: ' . auth_format_lager_date($lot['expiry_date'] ?? null) . '
'
. 'Hersteller: ' . auth_escape_html((string) ($lot['manufacturer_name'] ?? 'Nicht hinterlegt')) . '
'
. 'Hersteller-Chargennummer: ' . auth_escape_html((string) ($lot['manufacturer_lot_number'] ?? 'Nicht hinterlegt')) . '
'
. '
'
. auth_render_lager_documents($lot['documents'] ?? [], false, 'historical-' . (int) ($lot['lot_id'] ?? 0))
. '';
}
$html[] = '
';
}
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[] = '';
foreach (($product['open_lots'] ?? []) as $lot) {
$lotId = (int) ($lot['lot_id'] ?? 0);
$html[] = '
'
. ''
. 'Naurua-Chargennummer: ' . auth_escape_html((string) ($lot['lot_number'] ?? 'Nicht hinterlegt')) . '
'
. 'Status: Vorbereitet
'
. 'Bestand: ' . auth_format_lager_quantity((float) ($lot['qty_net'] ?? 0)) . '
'
. 'Eingangsmenge: ' . auth_format_lager_quantity((float) ($lot['qty_in'] ?? 0)) . '
'
. 'Hersteller: ' . auth_escape_html((string) ($lot['manufacturer_name'] ?? 'Nicht hinterlegt')) . '
'
. 'Hersteller-Chargennummer: ' . auth_escape_html((string) ($lot['manufacturer_lot_number'] ?? 'Nicht hinterlegt')) . '
'
. 'Herstellungsdatum: ' . auth_format_lager_date($lot['mfg_date'] ?? null) . '
'
. 'MHD: ' . auth_format_lager_date($lot['expiry_date'] ?? null) . '
'
. 'Einkaufsdatum: ' . auth_format_lager_date($lot['purchase_date'] ?? null) . '
'
. auth_render_lager_documents($lot['documents'] ?? [], false, 'open-read-' . $lotId)
. ''
. auth_render_lager_documents($lot['documents'] ?? [], true, 'open-edit-' . $lotId)
. ''
. ''
. '
Leere Felder speichern?
Die folgenden Felder werden leer gespeichert:
'
. '
Möchtest du diese offene Charge wirklich löschen?
Du kannst das nicht rückgängig machen. Bestätige durch Eingabe von DELETE.
';
}
$html[] = '
';
}
return implode('', $html);
}
function auth_render_lager_content(array $lagerProducts, array $lagerArtikel, array $lagerManufacturers, string $csrfToken, string $sectionTitle = 'Lager'): string
{
$manufacturerOptions = '';
foreach ($lagerManufacturers as $manufacturer) {
$manufacturerOptions .= '';
}
$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 ''
. '
'
. '
'
. '
'
. '
';
}
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 .= '';
$otcProductRows .= '';
$otcProductRows .= '
';
}
if ($otcProductRows === '') {
$otcProductRows = 'Keine aktiven OTC-Produkte erfasst.
';
}
$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 '';
echo '';
echo '';
echo '';
echo '';
echo 'Naurua ERP';
echo '';
echo '';
echo '';
echo '';
echo '';
echo '';
echo '';
echo '
';
echo '';
echo '';
echo '';
echo '';
echo '
';
echo '';
echo '
Verkauf bestätigen
';
echo '
';
echo '
Gesamtzahl Flaschen: 0
';
echo '
Gesamtbetrag: CHF 0.00
';
echo '
';
echo '';
echo '';
echo '
';
echo '
';
echo '';
echo '
';
echo '';
echo '';
echo '';
echo '';
echo '';
}