diff --git a/arbeitskacheln/15_mobile.md b/arbeitskacheln/15_mobile.md index d3de9e9..93b2809 100644 --- a/arbeitskacheln/15_mobile.md +++ b/arbeitskacheln/15_mobile.md @@ -48,10 +48,8 @@ Details zu MOBILE-001 … MOBILE-005 (vollständig). - **Akzeptanzkriterien:** Scan bis Akte offen in wenigen Sekunden, Fehlerfall (kein QR erkannt/ungültiger Code) klar kommuniziert. - **Tests:** Scan-Erfolgs-/Fehlertest. -- **DoD:** deckt sich mit MABEA (`BarcodeScanner`-Komponente + Scan-Route bereits - vorhanden) — die Akte existiert seit 2026-09-05 (`/akte/objekt/{id}`), der Scan - routet aber noch zur Kontrolle statt dorthin. Kleiner Nachzug (Scan-Ziel ändern), - kein Neubau mehr. +- **DoD:** deckt sich 1:1 mit MABEA — Scan routet seit 2026-09-06 zur Akte + (`/akte/objekt/{id}`), von dort Kurzweg-Button "Kontrolle starten". ## MOBILE-003 — Offline-Grundgerüst (P2) diff --git a/frontend/src/pages/ObjektListPage.tsx b/frontend/src/pages/ObjektListPage.tsx index 4c6b7d0..bf6d4b5 100644 --- a/frontend/src/pages/ObjektListPage.tsx +++ b/frontend/src/pages/ObjektListPage.tsx @@ -5,9 +5,10 @@ import { apiRequest, ApiError } from "../api/client"; import type { Objekt } from "../api/types"; import { BarcodeScanner } from "../components/BarcodeScanner"; -// Prompt 11 Screen 1: Standort/Objekt wählen. Objekt-Code (Karte 10) → -// Direktsprung ins Kontroll-Screen, sonst füllt der Scan dasselbe Textfeld wie -// die manuelle Suche (Kamera fällt bei Etikettschaden auf Tippen zurück). +// Prompt 11 Screen 1: Standort/Objekt wählen. Objekt-Code (MOBILE-002) → +// Direktsprung zur Akte (Zielseite laut Kachel 15), sonst füllt der Scan +// dasselbe Textfeld wie die manuelle Suche (Kamera fällt bei Etikettschaden +// auf Tippen zurück). export function ObjektListPage() { const navigate = useNavigate(); const [objekte, setObjekte] = useState([]); @@ -27,7 +28,7 @@ export function ObjektListPage() { setScannerOffen(false); try { const objekt = await apiRequest(`/objekte/code/${encodeURIComponent(code)}`); - navigate(`/objekte/${objekt.id}/kontrolle`); + navigate(`/akte/objekt/${objekt.id}`); } catch (err) { if (err instanceof ApiError && err.status === 404) { setSuche(code); diff --git a/frontend/src/pages/admin/LagerSection.tsx b/frontend/src/pages/admin/LagerSection.tsx index cf7fa00..9c4e64c 100644 --- a/frontend/src/pages/admin/LagerSection.tsx +++ b/frontend/src/pages/admin/LagerSection.tsx @@ -16,9 +16,8 @@ const TYP_LABEL: Record = { lager: "Lager", }; -// WH-001..004+007 (Warehouse-Kern): Lagerort-Hierarchie, Lagerplätze, Bestand -// je Lagerplatz, Ein-/Auslagerung. Umlagerung (WH-005) und Inventur (WH-006) -// bewusst als Folgeschritt zurückgestellt (arbeitskacheln/07_warehouse.md). +// WH-001..005+007: Lagerort-Hierarchie, Lagerplätze, Bestand je Lagerplatz, +// Ein-/Auslagerung, Umlagerung. Inventur (WH-006) noch offen (arbeitskacheln/07_warehouse.md). export function LagerSection({ materialien, onFehler }: Props) { const [lagerorte, setLagerorte] = useState([]); const [lagerplaetze, setLagerplaetze] = useState([]); @@ -37,6 +36,7 @@ export function LagerSection({ materialien, onFehler }: Props) { const [buchungMaterial, setBuchungMaterial] = useState(""); const [buchungMenge, setBuchungMenge] = useState(""); const [buchungGrund, setBuchungGrund] = useState(""); + const [umlagernZiel, setUmlagernZiel] = useState(""); async function laden() { try { @@ -144,6 +144,30 @@ export function LagerSection({ materialien, onFehler }: Props) { } } + async function umlagern() { + if (ausgewaehlterPlatz === "" || umlagernZiel === "" || buchungMaterial === "" || !buchungMenge) { + onFehler("Ziel-Lagerplatz, Material und Menge angeben."); + return; + } + try { + await apiRequest(`/lagerplaetze/${ausgewaehlterPlatz}/umlagern`, { + method: "POST", + body: { + nach_lagerplatz_id: umlagernZiel, + material_id: buchungMaterial, + menge: buchungMenge, + grund: buchungGrund || null, + }, + }); + setBuchungMenge(""); + setBuchungGrund(""); + setUmlagernZiel(""); + await ladeBestandUndBewegungen(ausgewaehlterPlatz); + } catch { + onFehler("Umlagerung fehlgeschlagen (nicht genug Bestand oder Ziel = Quelle)."); + } + } + return (

Lager

@@ -280,6 +304,23 @@ export function LagerSection({ materialien, onFehler }: Props) { + +

Bestand