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

feat(production): Batch bei Produktionsstart automatisch erstellen (#73)

- BatchNumber in allen ProductionOrder-Endpoints via BatchRepository auflösen
- BatchCreationFailed Error-Variante statt generischem ValidationFailure
- bestBeforeDate-Berechnung als Recipe.calculateBestBeforeDate() in die Domain verschoben
This commit is contained in:
Sebastian Frick 2026-02-26 09:13:51 +01:00
parent 26adf21162
commit 600d0f9f06
20 changed files with 356 additions and 397 deletions

View file

@ -20,7 +20,7 @@ const STATUS_COLORS: Record<string, string> = {
CANCELLED: 'red',
};
type Mode = 'view' | 'menu' | 'start-batch-input' | 'reschedule-input';
type Mode = 'view' | 'menu' | 'reschedule-input';
export function ProductionOrderDetailScreen() {
const { params, back } = useNavigation();
@ -31,7 +31,6 @@ export function ProductionOrderDetailScreen() {
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);
@ -80,12 +79,11 @@ export function ProductionOrderDetailScreen() {
};
const handleStart = async () => {
if (!batchId.trim()) return;
const result = await startProductionOrder(orderId, { batchId: batchId.trim() });
const result = await startProductionOrder(orderId);
if (result) {
setSuccess('Produktion gestartet.');
const bn = result.batchNumber ? ` Charge: ${result.batchNumber}` : '';
setSuccess(`Produktion gestartet.${bn}`);
setMode('view');
setBatchId('');
}
};
@ -107,11 +105,6 @@ export function ProductionOrderDetailScreen() {
return;
}
if (mode === 'start-batch-input') {
if (key.escape) setMode('menu');
return;
}
if (mode === 'menu') {
if (key.upArrow) setMenuIndex((i) => Math.max(0, i - 1));
if (key.downArrow) setMenuIndex((i) => Math.min(menuItems.length - 1, i + 1));
@ -122,10 +115,7 @@ export function ProductionOrderDetailScreen() {
setMode('reschedule-input');
setNewDate('');
}
if (action === 'start') {
setMode('start-batch-input');
setBatchId('');
}
if (action === 'start') void handleStart();
}
if (key.escape) setMode('view');
return;
@ -218,22 +208,6 @@ export function ProductionOrderDetailScreen() {
</Box>
)}
{mode === 'start-batch-input' && (
<Box flexDirection="column" borderStyle="round" borderColor="yellow" paddingX={1}>
<Text color="yellow" bold>Chargen-ID eingeben:</Text>
<Box>
<Text color="gray"> </Text>
<TextInput
value={batchId}
onChange={setBatchId}
onSubmit={() => void handleStart()}
focus={true}
/>
</Box>
<Text color="gray" dimColor>Enter bestätigen · Escape abbrechen</Text>
</Box>
)}
{mode === 'reschedule-input' && (
<Box flexDirection="column" borderStyle="round" borderColor="yellow" paddingX={1}>
<Text color="yellow" bold>Neues Datum (YYYY-MM-DD):</Text>

View file

@ -1,5 +1,5 @@
import { useState, useCallback } from 'react';
import type { ProductionOrderDTO, CreateProductionOrderRequest, StartProductionOrderRequest, ProductionOrderFilter } from '@effigenix/api-client';
import type { ProductionOrderDTO, CreateProductionOrderRequest, ProductionOrderFilter } from '@effigenix/api-client';
import { client } from '../utils/api-client.js';
interface ProductionOrdersState {
@ -77,10 +77,10 @@ export function useProductionOrders() {
}
}, []);
const startProductionOrder = useCallback(async (id: string, request: StartProductionOrderRequest) => {
const startProductionOrder = useCallback(async (id: string) => {
setState((s) => ({ ...s, loading: true, error: null }));
try {
const productionOrder = await client.productionOrders.start(id, request);
const productionOrder = await client.productionOrders.start(id);
setState((s) => ({ ...s, productionOrder, loading: false, error: null }));
return productionOrder;
} catch (err) {

File diff suppressed because one or more lines are too long

View file

@ -115,7 +115,6 @@ export type {
ReserveStockRequest,
StockMovementDTO,
RecordStockMovementRequest,
StartProductionOrderRequest,
CountryDTO,
} from '@effigenix/types';

View file

@ -1,7 +1,7 @@
/** Production Orders resource Production BC. */
import type { AxiosInstance } from 'axios';
import type { ProductionOrderDTO, CreateProductionOrderRequest, StartProductionOrderRequest, RescheduleProductionOrderRequest } from '@effigenix/types';
import type { ProductionOrderDTO, CreateProductionOrderRequest, RescheduleProductionOrderRequest } from '@effigenix/types';
export type Priority = 'LOW' | 'NORMAL' | 'HIGH' | 'URGENT';
@ -28,7 +28,7 @@ export interface ProductionOrderFilter {
dateTo?: string;
}
export type { ProductionOrderDTO, CreateProductionOrderRequest, StartProductionOrderRequest, RescheduleProductionOrderRequest };
export type { ProductionOrderDTO, CreateProductionOrderRequest, RescheduleProductionOrderRequest };
const BASE = '/api/production/production-orders';
@ -58,8 +58,8 @@ export function createProductionOrdersResource(client: AxiosInstance) {
return res.data;
},
async start(id: string, request: StartProductionOrderRequest): Promise<ProductionOrderDTO> {
const res = await client.post<ProductionOrderDTO>(`${BASE}/${id}/start`, request);
async start(id: string): Promise<ProductionOrderDTO> {
const res = await client.post<ProductionOrderDTO>(`${BASE}/${id}/start`);
return res.data;
},

View file

@ -1702,6 +1702,7 @@ export interface components {
recipeId?: string;
status?: string;
batchId?: string;
batchNumber?: string;
plannedQuantity?: string;
plannedQuantityUnit?: string;
/** Format: date */
@ -1714,9 +1715,6 @@ export interface components {
/** Format: date-time */
updatedAt?: string;
};
StartProductionOrderRequest: {
batchId: string;
};
RescheduleProductionOrderRequest: {
/** Format: date */
newPlannedDate: string;
@ -3118,11 +3116,7 @@ export interface operations {
};
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["StartProductionOrderRequest"];
};
};
requestBody?: never;
responses: {
/** @description OK */
200: {

View file

@ -30,6 +30,5 @@ export type CancelBatchRequest = components['schemas']['CancelBatchRequest'];
// Production Order types
export type ProductionOrderDTO = components['schemas']['ProductionOrderResponse'];
export type CreateProductionOrderRequest = components['schemas']['CreateProductionOrderRequest'];
export type StartProductionOrderRequest = components['schemas']['StartProductionOrderRequest'];
export type RescheduleProductionOrderRequest = components['schemas']['RescheduleProductionOrderRequest'];
export type CancelProductionOrderRequest = components['schemas']['CancelProductionOrderRequest'];