1
0
Fork 0
mirror of https://github.com/s-frick/effigenix.git synced 2026-03-28 08:29:36 +01:00

fix(tui,seed): Seed-Batch-Nummern korrigieren und Produktionsergebnis anzeigen

Seed-Daten: BW-260223-01 → P-2026-02-23-001, LW-260222-01 → P-2026-02-22-001,
damit die Chargennummern dem BatchNumber-VO-Format entsprechen.

ProductionOrderDetailScreen: Rezeptname statt ID anzeigen, Batch-Daten
(Soll-/Ist-Menge, Ausschuss, Bemerkungen) bei verknüpfter Charge laden.
This commit is contained in:
Sebastian Frick 2026-02-26 08:49:19 +01:00
parent 417f8fcdae
commit 26adf21162
3 changed files with 72 additions and 12 deletions

View file

@ -1,8 +1,11 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect, useState, useCallback } from 'react';
import { Box, Text, useInput } from 'ink';
import TextInput from 'ink-text-input';
import { useNavigation } from '../../state/navigation-context.js';
import { useProductionOrders } from '../../hooks/useProductionOrders.js';
import { useRecipeNameLookup } from '../../hooks/useRecipeNameLookup.js';
import { client } from '../../utils/api-client.js';
import type { BatchDTO } from '@effigenix/api-client';
import { LoadingSpinner } from '../shared/LoadingSpinner.js';
import { ErrorDisplay } from '../shared/ErrorDisplay.js';
import { SuccessDisplay } from '../shared/SuccessDisplay.js';
@ -25,11 +28,13 @@ export function ProductionOrderDetailScreen() {
productionOrder, loading, error,
fetchProductionOrder, releaseProductionOrder, rescheduleProductionOrder, startProductionOrder, clearError,
} = useProductionOrders();
const { recipeName } = useRecipeNameLookup();
const [mode, setMode] = useState<Mode>('view');
const [menuIndex, setMenuIndex] = useState(0);
const [batchId, setBatchId] = useState('');
const [newDate, setNewDate] = useState('');
const [success, setSuccess] = useState<string | null>(null);
const [batch, setBatch] = useState<BatchDTO | null>(null);
const orderId = params.orderId ?? '';
@ -37,6 +42,19 @@ export function ProductionOrderDetailScreen() {
if (orderId) void fetchProductionOrder(orderId);
}, [fetchProductionOrder, orderId]);
const loadBatch = useCallback(async (id: string) => {
try {
const b = await client.batches.getById(id);
setBatch(b);
} catch (err) {
setBatch(null);
}
}, []);
useEffect(() => {
if (productionOrder?.batchId) void loadBatch(productionOrder.batchId);
}, [loadBatch, productionOrder?.batchId]);
const getMenuItems = () => {
const items: { label: string; action: string }[] = [];
const status = productionOrder?.status;
@ -154,13 +172,13 @@ export function ProductionOrderDetailScreen() {
<Box flexDirection="column" borderStyle="round" borderColor="gray" paddingX={1}>
<Box><Text color="gray">ID: </Text><Text>{productionOrder.id}</Text></Box>
<Box><Text color="gray">Rezept-ID: </Text><Text>{productionOrder.recipeId}</Text></Box>
<Box><Text color="gray">Rezept: </Text><Text>{recipeName(productionOrder.recipeId ?? '') ?? productionOrder.recipeId}</Text><Text color="gray" dimColor> ({productionOrder.recipeId})</Text></Box>
<Box><Text color="gray">Status: </Text><Text color={statusColor}>{statusLabel}</Text></Box>
<Box><Text color="gray">Menge: </Text><Text>{productionOrder.plannedQuantity} {productionOrder.plannedQuantityUnit}</Text></Box>
<Box><Text color="gray">Geplant am: </Text><Text>{productionOrder.plannedDate}</Text></Box>
<Box><Text color="gray">Priorität: </Text><Text>{prioLabel}</Text></Box>
{productionOrder.batchId && (
<Box><Text color="gray">Chargen-ID: </Text><Text>{productionOrder.batchId}</Text></Box>
<Box><Text color="gray">Chargen-Nr: </Text><Text>{batch?.batchNumber ?? productionOrder.batchId}</Text></Box>
)}
{productionOrder.notes && (
<Box><Text color="gray">Notizen: </Text><Text>{productionOrder.notes}</Text></Box>
@ -169,6 +187,25 @@ export function ProductionOrderDetailScreen() {
<Box><Text color="gray">Aktualisiert:</Text><Text> {updatedAt}</Text></Box>
</Box>
{batch && productionOrder.batchId && (
<Box flexDirection="column" borderStyle="round" borderColor="gray" paddingX={1}>
<Text color="cyan" bold>Produktionsergebnis</Text>
<Box><Text color="gray">Soll-Menge: </Text><Text>{batch.plannedQuantity} {batch.plannedQuantityUnit}</Text></Box>
{batch.actualQuantity && (
<Box><Text color="gray">Ist-Menge: </Text><Text color="green">{batch.actualQuantity} {batch.actualQuantityUnit}</Text></Box>
)}
{batch.waste && (
<Box><Text color="gray">Ausschuss: </Text><Text color="red">{batch.waste} {batch.wasteUnit}</Text></Box>
)}
{batch.remarks && (
<Box><Text color="gray">Bemerkungen: </Text><Text>{batch.remarks}</Text></Box>
)}
{batch.completedAt && (
<Box><Text color="gray">Abgeschl. am:</Text><Text> {new Date(batch.completedAt).toLocaleString('de-DE', { dateStyle: 'medium', timeStyle: 'short' })}</Text></Box>
)}
</Box>
)}
{mode === 'menu' && (
<Box flexDirection="column" borderStyle="round" borderColor="cyan" paddingX={1}>
<Text color="cyan" bold>Aktionen</Text>

View file

@ -0,0 +1,23 @@
import { useEffect, useMemo, useCallback } from 'react';
import { useRecipes } from './useRecipes.js';
export function useRecipeNameLookup() {
const { recipes, fetchRecipes } = useRecipes();
useEffect(() => {
void fetchRecipes();
}, [fetchRecipes]);
const recipeNames = useMemo(() => {
const map = new Map<string, string>();
for (const r of recipes) map.set(r.id, r.name);
return map;
}, [recipes]);
const recipeName = useCallback(
(id: string) => recipeNames.get(id) ?? null,
[recipeNames],
);
return { recipeName };
}