fix(mobile): MOBILE-002 Scan routet zur Akte statt zur Kontrolle
CI / backend-tests (push) Successful in 2m2s
CI / frontend-build (push) Successful in 18s

Scan-Ziel war noch auf den alten Kontroll-Direktsprung eingestellt,
obwohl die Akte (FILE-006) seit 2026-09-05 existiert. Kurzweg-Button
"Kontrolle starten" auf der Akte deckt den alten Ablauf weiter ab.
Frontend-Anzeigen-Audit über alle Epics ergab keine weiteren echten
Backend-fertig/Anzeige-fehlt-Lücken.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
This commit is contained in:
2026-09-06 09:42:26 +02:00
co-authored by Claude Sonnet 5
parent b33d1c83a9
commit 01263753bf
3 changed files with 51 additions and 11 deletions
+5 -4
View File
@@ -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<Objekt[]>([]);
@@ -27,7 +28,7 @@ export function ObjektListPage() {
setScannerOffen(false);
try {
const objekt = await apiRequest<Objekt>(`/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);
+44 -3
View File
@@ -16,9 +16,8 @@ const TYP_LABEL: Record<LagerortTyp, string> = {
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<Lagerort[]>([]);
const [lagerplaetze, setLagerplaetze] = useState<Lagerplatz[]>([]);
@@ -37,6 +36,7 @@ export function LagerSection({ materialien, onFehler }: Props) {
const [buchungMaterial, setBuchungMaterial] = useState<number | "">("");
const [buchungMenge, setBuchungMenge] = useState("");
const [buchungGrund, setBuchungGrund] = useState("");
const [umlagernZiel, setUmlagernZiel] = useState<number | "">("");
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 (
<section className="section">
<h2>Lager</h2>
@@ -280,6 +304,23 @@ export function LagerSection({ materialien, onFehler }: Props) {
<button className="btn btn-secondary" onClick={() => buchen("auslagern")}>
Auslagern
</button>
<select
className="input"
value={umlagernZiel}
onChange={(e) => setUmlagernZiel(Number(e.target.value) || "")}
>
<option value="">Umlagern nach</option>
{lagerplaetze
.filter((p) => p.id !== ausgewaehlterPlatz)
.map((p) => (
<option key={p.id} value={p.id}>
{p.code}
</option>
))}
</select>
<button className="btn btn-secondary" onClick={umlagern}>
Verschieben
</button>
</div>
<h4>Bestand</h4>