소스 검색

adding docs

Medowar 6 일 전
부모
커밋
769246081c
6개의 변경된 파일569개의 추가작업 그리고 0개의 파일을 삭제
  1. 2 0
      README.md
  2. 2 0
      docs/.htaccess
  3. 214 0
      docs/SHOP_LOGIC.md
  4. 200 0
      docs/assets/docs.css
  5. 11 0
      docs/assets/marked.min.js
  6. 140 0
      docs/index.php

+ 2 - 0
README.md

@@ -42,6 +42,8 @@ Dieses Projekt ist ein internes Bestellsystem für persönliche Schutzausrüstun
 
 Weitere Konstanten: [docs/CONFIG_REFERENCE.md](docs/CONFIG_REFERENCE.md).
 
+Technische Dokumentation im Browser: [docs/index.php](docs/index.php) (Markdown wird mit [marked](https://marked.js.org/) gerendert).
+
 ## Hinweise
 
 - Bestellungen werden nicht im Browser für Endnutzer gespeichert oder nachverfolgt.

+ 2 - 0
docs/.htaccess

@@ -0,0 +1,2 @@
+# Documentation viewer: PHP serves Markdown; raw .md stays blocked by parent rules.
+Options -Indexes

+ 214 - 0
docs/SHOP_LOGIC.md

@@ -0,0 +1,214 @@
+# Bestellportal Dokumentation
+
+Dieser Leitfaden erklärt, **wie Sie Bestellungen im Admin-Bereich bearbeiten**.
+
+Für technische Details siehe [ADMIN_BUSINESS_LOGIC.md](ADMIN_BUSINESS_LOGIC.md).
+
+---
+
+## Die wichtigsten Seiten
+
+
+| Seite                | Wofür Sie sie nutzen                                                |
+| -------------------- | ------------------------------------------------------------------- |
+| **Dashboard**        | Schneller Überblick: Was ist offen? Was muss heute erledigt werden? |
+| **Bestellliste**     | Alle Bestellungen suchen und filtern                                |
+| **Bestelldetail**    | Einzelne Bestellung öffnen, Positionen abhaken, stornieren          |
+| **Nachbestellungen** | Artikel, die extern nachbestellt werden müssen                      |
+| **Einstellungen**    | E-Mail-Adresse für interne Bestellbenachrichtigungen, PDF-Anhang    |
+
+
+Produkte, Kategorien, Organisationen, FAQ und Admin-Konten haben **nichts direkt mit dem Bestellstatus** zu tun — dort pflegen Sie Inhalte und Zugänge.
+
+---
+
+## Zwei Dinge pro Bestellung im Kopf behalten
+
+Jede Bestellung hat **zwei getrennte Informationen**:
+
+1. **Wie weit ist die Bestellung insgesamt?**
+  Offen → Teilweise erledigt → Erledigt (oder: Storniert)
+2. **Braucht ein einzelner Artikel eine Nachbestellung beim Lieferanten?**
+  Das gilt **pro Position**, nicht für die ganze Bestellung.
+
+Beides läuft unabhängig voneinander. Eine Position kann z. B. schon als „ausgegeben“ markiert sein, während gleichzeitig noch auf Lieferantenware gewartet wird.
+
+---
+
+## Status einer Bestellung — was die Bezeichnungen bedeuten
+
+In Listen und auf dem Dashboard sehen Sie eines dieser Labels:
+
+
+| Label                    | Bedeutung                                                        |
+| ------------------------ | ---------------------------------------------------------------- |
+| **Offen**                | Noch nichts ausgegeben — alles steht aus                         |
+| **Teilweise bearbeitet** | Einige Artikel sind schon raus, andere noch nicht                |
+| **Bearbeitet**           | Alles ausgegeben — Bestellung abgeschlossen                      |
+| **Storniert**            | Bestellung ist ungültig; nur noch „Stornierung aufheben“ möglich |
+
+
+**Storniert** hat immer Vorrang vor allen anderen Anzeigen.
+
+---
+
+## Status einer einzelnen Position
+
+### Ausgegeben oder noch offen?
+
+- Auf der **Bestelldetail**-Seite markieren Sie jede Position als **bearbeitet** (ausgegeben) oder **offen**.
+- Der Gesamtstatus der Bestellung passt sich automatisch an:
+  - Keine Position erledigt → **Offen**
+  - Alle erledigt → **Bearbeitet**
+  - Dazwischen → **Teilweise bearbeitet**
+
+### Nachbestellung nötig?
+
+
+| Anzeige                  | Bedeutung                                       | Was Sie tun                                      |
+| ------------------------ | ----------------------------------------------- | ------------------------------------------------ |
+| *(kein Hinweis)*         | Artikel ist normal offen — aus Lager abgeben    | Auf Bestelldetail ausgeben und abhaken           |
+| **Nachzubestellen**      | Artikel fehlt — muss extern bestellt werden     | Auf Seite **Nachbestellungen** weiterbearbeiten  |
+| **Wartet auf Lieferung** | Beim Lieferanten bestellt — Lieferung steht aus | Auf **Nachbestellungen** warten, bis Ware da ist |
+
+
+**Manuelle Nachbestellungen** sind Artikel, die Sie **ohne Kundenbestellung** selbst nachbestellen (z. B. Lagerauffüllung). Sie erscheinen nur unter **Nachbestellungen**.
+
+---
+
+## Wo finde ich was?
+
+### Dashboard
+
+**Zählkarten oben**
+
+- **Offen**, **Teilweise bearbeitet**, **Bearbeitet**, **Storniert** — Anzahl Bestellungen je Status
+- **Nachbestellung** — wie viele Positionen gerade nachbestellt werden oder auf Lieferung warten
+
+**„Letzte offene Bestellungen“**
+
+- Zeigt bis zu 5 Bestellungen, die noch Arbeit brauchen
+- Nur Bestellungen mit mindestens einer **noch nicht ausgegebenen** Position
+- Positionen mit Nachbestell-Status zählen hier **nicht** — die bearbeiten Sie unter **Nachbestellungen**
+
+**„Offene Positionen“**
+
+- Ihre **Arbeitsliste**: einzelne Artikel, die noch ausgegeben werden müssen
+- Älteste zuerst — gut zum systematischen Abarbeiten
+- Auch hier: Positionen in Nachbestellung erscheinen **nicht**
+
+### Bestellliste
+
+- Suchen nach Bestellnummer
+- Filtern nach: Alle, Offen, Teilweise bearbeitet, Bearbeitet, Storniert
+
+### Bestelldetail
+
+Hier bearbeiten Sie **eine konkrete Bestellung**:
+
+
+| Aktion                                    | Wann möglich                                                                  |
+| ----------------------------------------- | ----------------------------------------------------------------------------- |
+| Position als bearbeitet / offen markieren | Bestellung nicht storniert                                                    |
+| Als Nachbestellung markieren / aufheben   | Bestellung nicht storniert; nur solange noch **nicht** „Wartet auf Lieferung“ |
+| Bestellung stornieren                     | Nicht storniert und noch nicht vollständig erledigt                           |
+| Stornierung aufheben                      | Bestellung ist storniert                                                      |
+
+
+**Hinweise:**
+
+- „Als bearbeitet markieren“ **entfernt nicht** automatisch einen Nachbestell-Hinweis.
+- „Als Nachbestellung markieren“ geht **nicht** bei schon ausgegebenen Positionen.
+- Status **„Wartet auf Lieferung“** ändern Sie **nur** auf der Seite **Nachbestellungen** (nicht auf der Detailseite).
+
+### Nachbestellungen
+
+- Alle Positionen, die nachbestellt werden müssen oder auf Lieferung warten
+- Nach **Produkt und Größe** gruppiert — praktisch zum Sammelbestellen beim Lieferanten
+- **Manuelle Nachbestellung** hinzufügen über das Formular auf derselben Seite
+
+**Massenaktionen** (älteste zuerst):
+
+
+| Aktion                     | Wirkung                                                    |
+| -------------------------- | ---------------------------------------------------------- |
+| **Als bestellt markieren** | Extern bestellt → Status wird „Wartet auf Lieferung“       |
+| **Lieferung eingetroffen** | Ware ist da → Position ist wieder normal offen zur Ausgabe |
+
+
+---
+
+## Typische Abläufe — Schritt für Schritt
+
+### Neue Bestellung ausgeben
+
+1. **Dashboard** → „Offene Positionen“ oder „Letzte offene Bestellungen“
+2. Bestellung öffnen (**Details**)
+3. Jede Position **„Als bearbeitet markieren"**, sobald der Artikel raus ist
+4. Sind alle Positionen erledigt, steht die Bestellung automatisch auf **Bearbeitet**
+
+### Artikel nicht auf Lager
+
+1. **Bestelldetail** → Position **„Als Nachbestellung markieren"**
+2. Position verschwindet aus den Dashboard-Arbeitslisten
+3. **Nachbestellungen** → beim Lieferanten bestellen → **„Als bestellt markieren"**
+4. Ware angekommen → **„Lieferung eingetroffen"**
+5. Zurück auf **Bestelldetail** → Artikel ausgeben → **„Als bearbeitet markieren"**
+
+### Lager auffüllen (ohne Kundenbestellung)
+
+1. **Nachbestellungen** → Formular **„Manuelle Nachbestellung"**
+2. Produkt, Größe und Anzahl eintragen
+3. Weiter wie oben: bestellen → Lieferung → ggf. ausgeben
+
+### Bestellung stornieren
+
+1. **Bestelldetail** → **„Bestellung stornieren"** (nicht möglich, wenn schon vollständig erledigt)
+2. Optional einen Grund angeben
+3. Stornierte Bestellungen finden Sie in der Bestellliste unter Filter **Storniert**
+4. Fehler? **„Stornierung aufheben"** auf der Detailseite
+
+---
+
+## Einstellungen (Grundkonfiguration)
+
+Unter **Einstellungen** können Sie anpassen:
+
+- **Empfängeradresse für interne Bestellmails** — wohin Benachrichtigungen über neue Bestellungen gehen
+- **PDF an interne Bestell-E-Mails anhängen** — ja/nein
+
+Der Text auf der Startseite wird separat unter **FAQ** gepflegt.
+
+---
+
+## Kurz-Übersicht: Wo verschwindet eine Position?
+
+
+| Situation                           | Dashboard „Offene Positionen“ | Nachbestellungen                                 |
+| ----------------------------------- | ----------------------------- | ------------------------------------------------ |
+| Normal offen, noch nicht ausgegeben | Ja                            | Nein                                             |
+| Nachzubestellen                     | Nein                          | Ja                                               |
+| Wartet auf Lieferung                | Nein                          | Ja                                               |
+| Schon ausgegeben                    | Nein                          | Nein (außer Nachbestell-Hinweis bleibt bestehen) |
+| Bestellung storniert                | Nein                          | Nein                                             |
+
+
+---
+
+## Wenn etwas unerwartet wirkt
+
+- **Position fehlt auf dem Dashboard, Bestellung ist aber offen**  
+Wahrscheinlich ist sie als Nachbestellung markiert oder wartet auf Lieferung → **Nachbestellungen** prüfen.
+- **„Wartet auf Lieferung“ lässt sich auf der Detailseite nicht ändern**  
+Das ist beabsichtigt. Weiterbearbeitung nur über **Nachbestellungen**.
+- **Bestellung kann nicht storniert werden**  
+Entweder ist sie schon vollständig **Bearbeitet**, oder sie ist bereits storniert.
+
+---
+
+## Weitere Dokumentation
+
+- [ADMIN_BUSINESS_LOGIC.md](ADMIN_BUSINESS_LOGIC.md) — ausführliche Beschreibung für Operatoren und technische Details
+- [ADMIN_SYSTEM.md](ADMIN_SYSTEM.md) — Anmeldung und Admin-Konten
+- [ORDER_PROCESS.md](ORDER_PROCESS.md) — Ablauf aus Kundensicht (Bestellung aufgeben)
+

+ 200 - 0
docs/assets/docs.css

@@ -0,0 +1,200 @@
+:root {
+    color-scheme: light;
+    --docs-bg: #f5f6f8;
+    --docs-surface: #fff;
+    --docs-text: #1a1a1a;
+    --docs-muted: #5c6370;
+    --docs-accent: #003366;
+    --docs-border: #d8dde6;
+    --docs-code-bg: #eef1f5;
+    font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
+    line-height: 1.6;
+}
+
+*,
+*::before,
+*::after {
+    box-sizing: border-box;
+}
+
+body {
+    margin: 0;
+    background: var(--docs-bg);
+    color: var(--docs-text);
+}
+
+.docs-header {
+    background: var(--docs-accent);
+    color: #fff;
+}
+
+.docs-header-inner {
+    max-width: 72rem;
+    margin: 0 auto;
+    padding: 0.75rem 1.25rem;
+    display: flex;
+    align-items: center;
+    justify-content: space-between;
+    gap: 1rem;
+}
+
+.docs-brand,
+.docs-back {
+    color: inherit;
+    text-decoration: none;
+}
+
+.docs-back {
+    font-size: 0.9rem;
+    opacity: 0.9;
+}
+
+.docs-back:hover,
+.docs-brand:hover {
+    text-decoration: underline;
+}
+
+.docs-layout {
+    max-width: 72rem;
+    margin: 0 auto;
+    padding: 1.25rem;
+    display: grid;
+    grid-template-columns: minmax(12rem, 16rem) 1fr;
+    gap: 1.5rem;
+    align-items: start;
+}
+
+@media (max-width: 768px) {
+    .docs-layout {
+        grid-template-columns: 1fr;
+    }
+}
+
+.docs-nav {
+    background: var(--docs-surface);
+    border: 1px solid var(--docs-border);
+    border-radius: 0.5rem;
+    padding: 1rem;
+    position: sticky;
+    top: 1rem;
+}
+
+.docs-nav-title {
+    margin: 0 0 0.5rem;
+    font-size: 0.75rem;
+    text-transform: uppercase;
+    letter-spacing: 0.04em;
+    color: var(--docs-muted);
+}
+
+.docs-nav ul {
+    margin: 0;
+    padding: 0;
+    list-style: none;
+}
+
+.docs-nav li + li {
+    margin-top: 0.25rem;
+}
+
+.docs-nav a {
+    display: block;
+    padding: 0.35rem 0.5rem;
+    border-radius: 0.25rem;
+    color: var(--docs-accent);
+    text-decoration: none;
+    font-size: 0.9rem;
+}
+
+.docs-nav a:hover {
+    background: var(--docs-code-bg);
+}
+
+.docs-nav a[aria-current="page"] {
+    background: var(--docs-accent);
+    color: #fff;
+}
+
+.docs-main {
+    background: var(--docs-surface);
+    border: 1px solid var(--docs-border);
+    border-radius: 0.5rem;
+    padding: 1.5rem 2rem;
+    min-width: 0;
+}
+
+.docs-index-list {
+    padding-left: 1.25rem;
+}
+
+.docs-index-list a {
+    color: var(--docs-accent);
+}
+
+.markdown-body h1,
+.markdown-body h2,
+.markdown-body h3 {
+    line-height: 1.25;
+    margin-top: 1.5em;
+    margin-bottom: 0.5em;
+}
+
+.markdown-body h1:first-child {
+    margin-top: 0;
+}
+
+.markdown-body p,
+.markdown-body ul,
+.markdown-body ol,
+.markdown-body pre,
+.markdown-body table {
+    margin: 0.75em 0;
+}
+
+.markdown-body a {
+    color: var(--docs-accent);
+}
+
+.markdown-body code {
+    font-family: ui-monospace, "Cascadia Code", "Source Code Pro", monospace;
+    font-size: 0.9em;
+    background: var(--docs-code-bg);
+    padding: 0.1em 0.35em;
+    border-radius: 0.2em;
+}
+
+.markdown-body pre {
+    background: var(--docs-code-bg);
+    padding: 1rem;
+    overflow-x: auto;
+    border-radius: 0.35rem;
+}
+
+.markdown-body pre code {
+    padding: 0;
+    background: none;
+}
+
+.markdown-body table {
+    border-collapse: collapse;
+    width: 100%;
+    font-size: 0.95rem;
+}
+
+.markdown-body th,
+.markdown-body td {
+    border: 1px solid var(--docs-border);
+    padding: 0.4rem 0.6rem;
+    text-align: left;
+}
+
+.markdown-body th {
+    background: var(--docs-code-bg);
+}
+
+.markdown-body blockquote {
+    margin: 1em 0;
+    padding-left: 1em;
+    border-left: 4px solid var(--docs-border);
+    color: var(--docs-muted);
+}

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 11 - 0
docs/assets/marked.min.js


+ 140 - 0
docs/index.php

@@ -0,0 +1,140 @@
+<?php
+declare(strict_types=1);
+
+/**
+ * Simple documentation viewer (Markdown → HTML via marked).
+ */
+
+$docsDir = __DIR__;
+$docMap = [];
+
+foreach (glob($docsDir . '/*.md') ?: [] as $path) {
+    $base = basename($path, '.md');
+    if (preg_match('/^[A-Z0-9_]+$/', $base) !== 1) {
+        continue;
+    }
+    $docMap[$base] = $path;
+}
+
+ksort($docMap);
+
+$requested = isset($_GET['doc']) ? (string) $_GET['doc'] : '';
+$activeDoc = null;
+$markdown = null;
+$pageTitle = 'Dokumentation';
+
+if ($requested !== '') {
+    if (!isset($docMap[$requested])) {
+        http_response_code(404);
+        $pageTitle = 'Nicht gefunden';
+    } else {
+        $activeDoc = $requested;
+        $markdown = file_get_contents($docMap[$requested]);
+        if ($markdown === false) {
+            http_response_code(500);
+            $pageTitle = 'Fehler';
+            $markdown = null;
+        } else {
+            $pageTitle = docTitle($activeDoc);
+        }
+    }
+}
+
+function docTitle(string $key): string
+{
+    return ucwords(strtolower(str_replace('_', ' ', $key)));
+}
+
+function escape(string $value): string
+{
+    return htmlspecialchars($value, ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
+}
+
+$baseHref = rtrim(str_replace('\\', '/', dirname($_SERVER['SCRIPT_NAME'] ?? '/docs')), '/') . '/';
+if ($baseHref === '/') {
+    $baseHref = '/docs/';
+}
+?>
+<!DOCTYPE html>
+<html lang="de">
+<head>
+    <meta charset="UTF-8">
+    <meta name="viewport" content="width=device-width, initial-scale=1.0">
+    <title><?php echo escape($pageTitle); ?> – PSA Dokumentation</title>
+    <link rel="stylesheet" href="<?php echo escape($baseHref); ?>assets/docs.css">
+</head>
+<body>
+    <header class="docs-header">
+        <div class="docs-header-inner">
+            <a class="docs-brand" href="<?php echo escape($baseHref); ?>index.php">PSA Dokumentation</a>
+            <a class="docs-back" href="../index.php">Zur Anwendung</a>
+        </div>
+    </header>
+    <div class="docs-layout">
+        <nav class="docs-nav" aria-label="Dokumentation">
+            <p class="docs-nav-title">Inhalt</p>
+            <ul>
+                <?php foreach ($docMap as $key => $_path): ?>
+                    <li>
+                        <a href="<?php echo escape($baseHref); ?>index.php?doc=<?php echo escape($key); ?>"
+                           <?php echo $key === $activeDoc ? 'aria-current="page"' : ''; ?>>
+                            <?php echo escape(docTitle($key)); ?>
+                        </a>
+                    </li>
+                <?php endforeach; ?>
+            </ul>
+        </nav>
+        <main class="docs-main">
+            <?php if ($requested === ''): ?>
+                <h1>Dokumentation</h1>
+                <p>Technische und fachliche Hinweise zum PSA-Bestellsystem.</p>
+                <ul class="docs-index-list">
+                    <?php foreach ($docMap as $key => $_path): ?>
+                        <li>
+                            <a href="<?php echo escape($baseHref); ?>index.php?doc=<?php echo escape($key); ?>">
+                                <?php echo escape(docTitle($key)); ?>
+                            </a>
+                        </li>
+                    <?php endforeach; ?>
+                </ul>
+            <?php elseif ($markdown === null): ?>
+                <h1><?php echo escape($pageTitle); ?></h1>
+                <p>Das angeforderte Dokument ist nicht verfügbar.</p>
+                <p><a href="<?php echo escape($baseHref); ?>index.php">Zur Übersicht</a></p>
+            <?php else: ?>
+                <article id="doc-content" class="markdown-body"></article>
+                <script type="application/json" id="doc-source"><?php
+                    echo json_encode(
+                        $markdown,
+                        JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT | JSON_UNESCAPED_UNICODE
+                    );
+                ?></script>
+            <?php endif; ?>
+        </main>
+    </div>
+    <?php if ($markdown !== null): ?>
+        <script src="<?php echo escape($baseHref); ?>assets/marked.min.js"></script>
+        <script>
+            (function () {
+                var source = document.getElementById('doc-source');
+                var target = document.getElementById('doc-content');
+                if (!source || !target || typeof marked === 'undefined') {
+                    return;
+                }
+                var text = JSON.parse(source.textContent || '""');
+                target.innerHTML = marked.parse(text, { gfm: true, breaks: false });
+                target.querySelectorAll('a[href]').forEach(function (link) {
+                    var href = link.getAttribute('href');
+                    if (!href || /^[a-z]+:/i.test(href) || href.charAt(0) === '#') {
+                        return;
+                    }
+                    var name = href.split('/').pop().replace(/\.md$/i, '');
+                    if (/^[A-Z0-9_]+$/i.test(name)) {
+                        link.setAttribute('href', 'index.php?doc=' + encodeURIComponent(name.toUpperCase()));
+                    }
+                });
+            })();
+        </script>
+    <?php endif; ?>
+</body>
+</html>

이 변경점에서 너무 많은 파일들이 변경되어 몇몇 파일들은 표시되지 않았습니다.