diff --git a/backend/src/controllers/ausruestungsanfrage.controller.ts b/backend/src/controllers/ausruestungsanfrage.controller.ts index 05510e5..7d78fa4 100644 --- a/backend/src/controllers/ausruestungsanfrage.controller.ts +++ b/backend/src/controllers/ausruestungsanfrage.controller.ts @@ -573,6 +573,7 @@ class AusruestungsanfrageController { groesse?: string; kategorie?: string; eigenschaften?: Array<{ eigenschaft_id?: number; name: string; wert: string }>; + replacedItemIds?: string[]; }>; }; diff --git a/backend/src/controllers/personalEquipment.controller.ts b/backend/src/controllers/personalEquipment.controller.ts index c032fe4..e559c2f 100644 --- a/backend/src/controllers/personalEquipment.controller.ts +++ b/backend/src/controllers/personalEquipment.controller.ts @@ -34,6 +34,7 @@ const CreateSchema = z.object({ anschaffung_datum: isoDate.optional(), zustand: ZustandEnum.optional(), notizen: z.string().max(2000).optional(), + menge: z.number().int().min(1).default(1).optional(), eigenschaften: z.array(EigenschaftInput).optional(), }); @@ -49,6 +50,7 @@ const UpdateSchema = z.object({ anschaffung_datum: isoDate.nullable().optional(), zustand: ZustandEnum.optional(), notizen: z.string().max(2000).nullable().optional(), + menge: z.number().int().min(1).nullable().optional(), eigenschaften: z.array(EigenschaftInput).nullable().optional(), }); diff --git a/backend/src/database/migrations/100_add_menge_to_persoenliche_ausruestung.sql b/backend/src/database/migrations/100_add_menge_to_persoenliche_ausruestung.sql new file mode 100644 index 0000000..0b3f69a --- /dev/null +++ b/backend/src/database/migrations/100_add_menge_to_persoenliche_ausruestung.sql @@ -0,0 +1 @@ +ALTER TABLE persoenliche_ausruestung ADD COLUMN IF NOT EXISTS menge INT NOT NULL DEFAULT 1; diff --git a/backend/src/services/ausruestungsanfrage.service.ts b/backend/src/services/ausruestungsanfrage.service.ts index bddee96..acb6345 100644 --- a/backend/src/services/ausruestungsanfrage.service.ts +++ b/backend/src/services/ausruestungsanfrage.service.ts @@ -1007,6 +1007,7 @@ interface AssignmentInput { groesse?: string; kategorie?: string; eigenschaften?: { eigenschaft_id?: number; name: string; wert: string }[]; + replacedItemIds?: string[]; } async function assignDeliveredItems( @@ -1033,7 +1034,7 @@ async function assignDeliveredItems( for (const a of assignments) { // Load position details const posResult = await client.query( - 'SELECT bezeichnung, artikel_id FROM ausruestung_anfrage_positionen WHERE id = $1 AND anfrage_id = $2', + 'SELECT bezeichnung, artikel_id, menge FROM ausruestung_anfrage_positionen WHERE id = $1 AND anfrage_id = $2', [a.positionId, anfrageId], ); if (posResult.rows.length === 0) continue; @@ -1088,8 +1089,8 @@ async function assignDeliveredItems( const insertResult = await client.query( `INSERT INTO persoenliche_ausruestung ( bezeichnung, kategorie, groesse, user_id, benutzer_name, - anfrage_id, anfrage_position_id, artikel_id, erstellt_von - ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) + anfrage_id, anfrage_position_id, artikel_id, menge, erstellt_von + ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) RETURNING id`, [ pos.bezeichnung, @@ -1100,6 +1101,7 @@ async function assignDeliveredItems( anfrageId, a.positionId, pos.artikel_id ?? null, + pos.menge ?? 1, requestingUserId, ], ); @@ -1146,6 +1148,15 @@ async function assignDeliveredItems( ); } + if (a.replacedItemIds && a.replacedItemIds.length > 0) { + await client.query( + `UPDATE persoenliche_ausruestung + SET geloescht_am = NOW() + WHERE id = ANY($1::uuid[]) AND geloescht_am IS NULL`, + [a.replacedItemIds], + ); + } + assigned++; } diff --git a/backend/src/services/personalEquipment.service.ts b/backend/src/services/personalEquipment.service.ts index b0f9169..091016c 100644 --- a/backend/src/services/personalEquipment.service.ts +++ b/backend/src/services/personalEquipment.service.ts @@ -19,6 +19,7 @@ interface CreatePersonalEquipmentData { anschaffung_datum?: string; zustand?: string; notizen?: string; + menge?: number; eigenschaften?: { eigenschaft_id?: number | null; name: string; wert: string }[]; } @@ -34,6 +35,7 @@ interface UpdatePersonalEquipmentData { anschaffung_datum?: string | null; zustand?: string; notizen?: string | null; + menge?: number | null; eigenschaften?: { eigenschaft_id?: number | null; name: string; wert: string }[] | null; } @@ -154,8 +156,8 @@ async function create(data: CreatePersonalEquipmentData, requestingUserId: strin `INSERT INTO persoenliche_ausruestung ( bezeichnung, kategorie, artikel_id, user_id, benutzer_name, groesse, seriennummer, inventarnummer, anschaffung_datum, - zustand, notizen, erstellt_von - ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12) + zustand, notizen, menge, erstellt_von + ) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13) RETURNING *`, [ data.bezeichnung, @@ -169,6 +171,7 @@ async function create(data: CreatePersonalEquipmentData, requestingUserId: strin data.anschaffung_datum ?? null, data.zustand ?? 'gut', data.notizen ?? null, + data.menge ?? 1, requestingUserId, ], ); @@ -214,6 +217,7 @@ async function update(id: string, data: UpdatePersonalEquipmentData) { if (data.anschaffung_datum !== undefined) addField('anschaffung_datum', data.anschaffung_datum); if (data.zustand !== undefined) addField('zustand', data.zustand); if (data.notizen !== undefined) addField('notizen', data.notizen); + if (data.menge !== undefined) addField('menge', data.menge ?? 1); if (fields.length === 0 && data.eigenschaften === undefined) { throw new Error('No fields to update'); diff --git a/frontend/src/components/dashboard/PersoenlicheAusruestungWidget.tsx b/frontend/src/components/dashboard/PersoenlicheAusruestungWidget.tsx index bee0f7a..4159bad 100644 --- a/frontend/src/components/dashboard/PersoenlicheAusruestungWidget.tsx +++ b/frontend/src/components/dashboard/PersoenlicheAusruestungWidget.tsx @@ -1,4 +1,4 @@ -import { List, ListItem, ListItemText, Chip, Typography } from '@mui/material'; +import { Box, List, ListItem, ListItemText, Chip, Typography } from '@mui/material'; import CheckroomIcon from '@mui/icons-material/Checkroom'; import { useQuery } from '@tanstack/react-query'; import { useNavigate } from 'react-router-dom'; @@ -51,11 +51,17 @@ function PersoenlicheAusruestungWidget() { {displayItems.map((item) => ( + {item.bezeichnung} + {item.menge > 1 && ( + + )} + + } secondary={item.artikel_kategorie_parent_name ? `${item.artikel_kategorie_parent_name} > ${item.artikel_kategorie_name}` : item.artikel_kategorie_name ?? item.kategorie ?? undefined} - primaryTypographyProps={{ variant: 'body2', noWrap: true }} secondaryTypographyProps={{ variant: 'caption' }} /> (null); const [catalogItems, setCatalogItems] = useState([{ bezeichnung: '', menge: 1 }]); const [freeItems, setFreeItems] = useState<{ bezeichnung: string; menge: number }[]>([]); - const [assignedSelections, setAssignedSelections] = useState>({}); + const [replacementSelections, setReplacementSelections] = useState>({}); const [catalogIstErsatz, setCatalogIstErsatz] = useState>({}); const [freeIstErsatz, setFreeIstErsatz] = useState>({}); @@ -96,15 +95,6 @@ export default function AusruestungsanfrageNeu() { queryFn: () => ausruestungsanfrageApi.getItems({ aktiv: true }), }); - const { data: zustandOptions = [] } = useQuery({ - queryKey: ['persoenliche-ausruestung', 'zustand-options'], - queryFn: () => personalEquipmentApi.getZustandOptions(), - staleTime: 5 * 60 * 1000, - }); - - const getZustandLabel = (key: string) => zustandOptions.find(o => o.key === key)?.label ?? key; - const getZustandColor = (key: string) => zustandOptions.find(o => o.key === key)?.color ?? 'default'; - const { data: orderUsers = [] } = useQuery({ queryKey: ['ausruestungsanfrage', 'orderUsers'], queryFn: () => ausruestungsanfrageApi.getOrderUsers(), @@ -121,19 +111,48 @@ export default function AusruestungsanfrageNeu() { staleTime: 2 * 60 * 1000, }); - // Clear assigned selections when switching user + // Clear replacement selections when switching user const prevTargetUserRef = useRef(targetUserId); useEffect(() => { if (prevTargetUserRef.current !== targetUserId) { - setAssignedSelections({}); + setReplacementSelections({}); prevTargetUserRef.current = targetUserId; } }, [targetUserId]); + // Group personal items by artikel_id (skip items without artikel_id) + const personalItemGroups = useMemo(() => { + const groups = new Map(); + for (const item of myPersonalItems) { + if (!item.artikel_id) continue; + const itemMenge = item.menge; + const existing = groups.get(item.artikel_id); + if (existing) { + existing.totalMenge += itemMenge; + for (const e of item.eigenschaften ?? []) { + if (!existing.eigenschaften.some(x => x.name === e.name && x.wert === e.wert)) { + existing.eigenschaften.push({ name: e.name, wert: e.wert }); + } + } + } else { + groups.set(item.artikel_id, { + bezeichnung: item.artikel_bezeichnung || item.bezeichnung, + totalMenge: itemMenge, + eigenschaften: (item.eigenschaften ?? []).map(e => ({ name: e.name, wert: e.wert })), + }); + } + } + return groups; + }, [myPersonalItems]); + // ── Mutations ── const createMut = useMutation({ - mutationFn: (args: { items: AusruestungAnfrageFormItem[]; notizen?: string; bezeichnung?: string; fuer_benutzer_id?: string; fuer_benutzer_name?: string; assignedItems?: { persoenlich_id: string; neuer_zustand: string }[] }) => - ausruestungsanfrageApi.createRequest(args.items, args.notizen, args.bezeichnung, args.fuer_benutzer_id, args.fuer_benutzer_name, args.assignedItems), + mutationFn: (args: { items: AusruestungAnfrageFormItem[]; notizen?: string; bezeichnung?: string; fuer_benutzer_id?: string; fuer_benutzer_name?: string }) => + ausruestungsanfrageApi.createRequest(args.items, args.notizen, args.bezeichnung, args.fuer_benutzer_id, args.fuer_benutzer_name), onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['ausruestungsanfrage'] }); showSuccess('Anfrage erstellt'); @@ -171,7 +190,21 @@ export default function AusruestungsanfrageNeu() { .filter(i => i.bezeichnung.trim()) .map((i, idx) => ({ bezeichnung: i.bezeichnung, menge: i.menge, ist_ersatz: freeIstErsatz[idx] || false })); - const allItems = [...catalogValidItems, ...freeValidItems]; + // Replacement items (from grouped personal items) + const replacementItems: AusruestungAnfrageFormItem[] = Object.entries(replacementSelections) + .filter(([, menge]) => menge > 0) + .map(([artikelIdStr, menge]) => { + const artikelId = Number(artikelIdStr); + const group = personalItemGroups.get(artikelId); + return { + artikel_id: artikelId, + bezeichnung: group?.bezeichnung ?? '', + menge, + ist_ersatz: true, + }; + }); + + const allItems = [...catalogValidItems, ...freeValidItems, ...replacementItems]; if (allItems.length === 0) return; // Check required eigenschaften for catalog items @@ -194,13 +227,10 @@ export default function AusruestungsanfrageNeu() { bezeichnung: bezeichnung || undefined, fuer_benutzer_id: typeof fuerBenutzer === 'object' && fuerBenutzer ? fuerBenutzer.id : undefined, fuer_benutzer_name: typeof fuerBenutzer === 'string' ? fuerBenutzer : undefined, - assignedItems: Object.entries(assignedSelections) - .filter(([, v]) => !!v) - .map(([id, neuer_zustand]) => ({ persoenlich_id: id, neuer_zustand })), }); }; - const hasValidItems = catalogItems.some(i => !!i.artikel_id) || freeItems.some(i => i.bezeichnung.trim()) || Object.keys(assignedSelections).length > 0; + const hasValidItems = catalogItems.some(i => !!i.artikel_id) || freeItems.some(i => i.bezeichnung.trim()) || Object.values(replacementSelections).some(m => m > 0); return ( @@ -347,55 +377,58 @@ export default function AusruestungsanfrageNeu() { - Zugewiesene Gegenstände - {myPersonalItems.length === 0 ? ( - Keine zugewiesenen Gegenstände vorhanden. + Zugewiesene Gegenstände (für Ersatz) + {personalItemGroups.size === 0 ? ( + + {targetUserId || !canOrderForUser ? 'Keine zugewiesenen Gegenstände vorhanden.' : 'Wähle einen Benutzer, um zugewiesene Gegenstände zu sehen.'} + ) : ( - myPersonalItems.map((item) => ( - - - { - if (e.target.checked) { - setAssignedSelections(prev => ({ ...prev, [item.id]: item.zustand })); - if (item.artikel_id) loadEigenschaften(item.artikel_id); - } else { - setAssignedSelections(prev => { const n = { ...prev }; delete n[item.id]; return n; }); - } - }} - /> - {item.bezeichnung} - {item.eigenschaften && item.eigenschaften.length > 0 && ( - - {item.eigenschaften.map(e => ( - - ))} - - )} - - {!!assignedSelections[item.id] && ( - { + const selectedMenge = replacementSelections[artikelId] ?? 0; + const checked = selectedMenge > 0; + return ( + + setAssignedSelections(prev => ({ ...prev, [item.id]: e.target.value }))} - > - {zustandOptions.map((opt) => ( - {opt.label} - ))} - - )} + checked={checked} + onChange={(e) => { + if (e.target.checked) { + setReplacementSelections(prev => ({ ...prev, [artikelId]: 1 })); + } else { + setReplacementSelections(prev => { + const n = { ...prev }; + delete n[artikelId]; + return n; + }); + } + }} + /> + {group.bezeichnung} + + {group.eigenschaften.length > 0 && ( + + {group.eigenschaften.map((e, i) => ( + + ))} + + )} + {checked && ( + { + const v = Math.max(1, Math.min(group.totalMenge, Number(e.target.value) || 1)); + setReplacementSelections(prev => ({ ...prev, [artikelId]: v })); + }} + inputProps={{ min: 1, max: group.totalMenge }} + sx={{ width: 130 }} + /> + )} - - )) + ); + }) )} diff --git a/frontend/src/pages/AusruestungsanfrageZuweisung.tsx b/frontend/src/pages/AusruestungsanfrageZuweisung.tsx index 9b8c330..eeae2c8 100644 --- a/frontend/src/pages/AusruestungsanfrageZuweisung.tsx +++ b/frontend/src/pages/AusruestungsanfrageZuweisung.tsx @@ -2,7 +2,7 @@ import { useState, useMemo } from 'react'; import { Box, Typography, Container, Button, Chip, TextField, Autocomplete, ToggleButton, ToggleButtonGroup, - Stack, Divider, LinearProgress, MenuItem, + Stack, Divider, LinearProgress, MenuItem, Checkbox, FormControlLabel, } from '@mui/material'; import { Assignment as AssignmentIcon } from '@mui/icons-material'; import { useQuery, useQueryClient } from '@tanstack/react-query'; @@ -16,6 +16,7 @@ import { personalEquipmentApi } from '../services/personalEquipment'; import { vehiclesApi } from '../services/vehicles'; import { membersService } from '../services/members'; import type { AusruestungAnfragePosition, AusruestungEigenschaft } from '../types/ausruestungsanfrage.types'; +import type { ZustandOption } from '../types/personalEquipment.types'; type AssignmentTyp = 'ausruestung' | 'persoenlich' | 'keine'; @@ -130,13 +131,34 @@ export default function AusruestungsanfrageZuweisung() { staleTime: 2 * 60 * 1000, }); + const { data: zustandOptions = [] } = useQuery({ + queryKey: ['persoenliche-ausruestung', 'zustand-options'], + queryFn: () => personalEquipmentApi.getZustandOptions(), + staleTime: 5 * 60 * 1000, + }); + + const getZustandLabel = (key: string) => zustandOptions.find(o => o.key === key)?.label ?? key; + const getZustandColor = (key: string) => zustandOptions.find(o => o.key === key)?.color ?? 'default'; + const [submitting, setSubmitting] = useState(false); + const [replacements, setReplacements] = useState>({}); const updateAssignment = (posId: number, patch: Partial) => { - setAssignments((prev) => ({ - ...prev, - [posId]: { ...prev[posId], ...patch }, - })); + setAssignments((prev) => { + const prevA = prev[posId]; + // If userId changes, clear replacements for this position + if (patch.userId !== undefined && prevA?.userId !== patch.userId) { + setReplacements((r) => { + const n = { ...r }; + delete n[posId]; + return n; + }); + } + return { + ...prev, + [posId]: { ...prevA, ...patch }, + }; + }); }; const handleSkipAll = () => { @@ -190,6 +212,7 @@ export default function AusruestungsanfrageZuweisung() { wert, })) : undefined, + replacedItemIds: pos?.ist_ersatz ? (replacements[Number(posId)] ?? []) : undefined, }; }); await ausruestungsanfrageApi.assignItems(anfrageId, payload); @@ -369,6 +392,65 @@ export default function AusruestungsanfrageZuweisung() { /> ) )} + {pos.ist_ersatz && a.userId && pos.artikel_id && (() => { + const oldItems = allPersonalItems.filter( + i => i.artikel_id === pos.artikel_id && i.user_id === a.userId, + ); + if (oldItems.length === 0) return null; + const selectedIds = replacements[pos.id] ?? []; + const selectedTotal = oldItems + .filter(i => selectedIds.includes(i.id)) + .reduce((sum, i) => sum + i.menge, 0); + const limitReached = selectedTotal >= pos.menge; + return ( + + + Alte Gegenstände ersetzen ({selectedTotal} / {pos.menge}) + + + {oldItems.map(item => { + const isChecked = selectedIds.includes(item.id); + const itemMenge = item.menge; + return ( + { + setReplacements(prev => { + const cur = prev[pos.id] ?? []; + const next = ev.target.checked + ? [...cur, item.id] + : cur.filter(x => x !== item.id); + return { ...prev, [pos.id]: next }; + }); + }} + /> + } + label={ + + {item.bezeichnung} + + {(item.eigenschaften ?? []).map(e => ( + + ))} + + + } + /> + ); + })} + + + ); + })()} )} diff --git a/frontend/src/pages/MitgliedDetail.tsx b/frontend/src/pages/MitgliedDetail.tsx index 4838312..8ed7ed0 100644 --- a/frontend/src/pages/MitgliedDetail.tsx +++ b/frontend/src/pages/MitgliedDetail.tsx @@ -882,7 +882,12 @@ function MitgliedDetail() { onClick={() => navigate(`/persoenliche-ausruestung/${item.id}`)} > - {item.bezeichnung} + + {item.bezeichnung} + {item.menge > 1 && ( + + )} + {item.kategorie && ( {item.kategorie} )} diff --git a/frontend/src/pages/PersoenlicheAusruestung.tsx b/frontend/src/pages/PersoenlicheAusruestung.tsx index 5720432..136a5ee 100644 --- a/frontend/src/pages/PersoenlicheAusruestung.tsx +++ b/frontend/src/pages/PersoenlicheAusruestung.tsx @@ -181,6 +181,7 @@ function PersoenlicheAusruestungPage() { Bezeichnung Kategorie + Menge {canSeeAll && Benutzer} Zustand @@ -188,7 +189,7 @@ function PersoenlicheAusruestungPage() { {isLoading ? ( - + Lade Daten… @@ -196,7 +197,7 @@ function PersoenlicheAusruestungPage() { ) : filtered.length === 0 ? ( - + @@ -236,6 +237,9 @@ function PersoenlicheAusruestungPage() { ? `${item.artikel_kategorie_parent_name} > ${item.artikel_kategorie_name}` : item.artikel_kategorie_name ?? item.kategorie ?? '—'} + + {item.menge > 1 && } + {canSeeAll && ( diff --git a/frontend/src/pages/PersoenlicheAusruestungDetail.tsx b/frontend/src/pages/PersoenlicheAusruestungDetail.tsx index 86e8570..ebc7620 100644 --- a/frontend/src/pages/PersoenlicheAusruestungDetail.tsx +++ b/frontend/src/pages/PersoenlicheAusruestungDetail.tsx @@ -102,6 +102,7 @@ export default function PersoenlicheAusruestungDetail() { {([ ['Benutzer', item.user_display_name || item.benutzer_name], + ['Menge', item.menge > 1 ? String(item.menge) : null], ['Seriennummer', item.seriennummer], ['Inventarnummer', item.inventarnummer], ['Erstellt am', new Date(item.erstellt_am).toLocaleDateString('de-AT')], diff --git a/frontend/src/pages/PersoenlicheAusruestungEdit.tsx b/frontend/src/pages/PersoenlicheAusruestungEdit.tsx index 1854b23..cf9de45 100644 --- a/frontend/src/pages/PersoenlicheAusruestungEdit.tsx +++ b/frontend/src/pages/PersoenlicheAusruestungEdit.tsx @@ -82,6 +82,7 @@ export default function PersoenlicheAusruestungEdit() { const [seriennummer, setSeriennummer] = useState(''); const [inventarnummer, setInventarnummer] = useState(''); const [zustand, setZustand] = useState('gut'); + const [menge, setMenge] = useState(1); const [notizen, setNotizen] = useState(''); const [userId, setUserId] = useState<{ id: string; name: string } | null>(null); const [eigenschaften, setEigenschaften] = useState([]); @@ -93,6 +94,7 @@ export default function PersoenlicheAusruestungEdit() { setSeriennummer(item.seriennummer ?? ''); setInventarnummer(item.inventarnummer ?? ''); setZustand(item.zustand); + setMenge(item.menge ?? 1); setNotizen(item.notizen ?? ''); if (item.eigenschaften) { setEigenschaften(item.eigenschaften.map(e => ({ @@ -141,6 +143,7 @@ export default function PersoenlicheAusruestungEdit() { seriennummer: seriennummer || null, inventarnummer: inventarnummer || null, zustand, + menge, notizen: notizen || null, eigenschaften: item.artikel_id ? Object.entries(catalogEigenschaftValues) @@ -231,6 +234,16 @@ export default function PersoenlicheAusruestungEdit() { onChange={(e) => setInventarnummer(e.target.value)} /> + setMenge(Math.max(1, parseInt(e.target.value, 10) || 1))} + inputProps={{ min: 1 }} + sx={{ width: 120 }} + /> + (null); const [formBenutzerName, setFormBenutzerName] = useState(''); const [formZustand, setFormZustand] = useState('gut'); + const [formMenge, setFormMenge] = useState(1); const [formNotizen, setFormNotizen] = useState(''); const [eigenschaftValues, setEigenschaftValues] = useState>({}); @@ -93,6 +94,7 @@ export default function PersoenlicheAusruestungNeu() { user_id: formUserId?.id || undefined, benutzer_name: formBenutzerName || undefined, zustand: formZustand, + menge: formMenge, notizen: formNotizen || undefined, eigenschaften: Object.entries(eigenschaftValues) .filter(([, v]) => v.trim()) @@ -179,6 +181,16 @@ export default function PersoenlicheAusruestungNeu() { ))} + setFormMenge(Math.max(1, parseInt(e.target.value, 10) || 1))} + inputProps={{ min: 1 }} + sx={{ width: 120 }} + /> + => { - // Merge assigned personal items into the items array with ist_ersatz: true - const allItems = [ - ...items, - ...(assignedItems ?? []).map(a => ({ - bezeichnung: '', // backend resolves from persoenlich_id - menge: 1, - persoenlich_id: a.persoenlich_id, - neuer_zustand: a.neuer_zustand, - ist_ersatz: true, - })), - ]; - const r = await api.post('/api/ausruestungsanfragen/requests', { items: allItems, notizen, bezeichnung, fuer_benutzer_id, fuer_benutzer_name }); + const r = await api.post('/api/ausruestungsanfragen/requests', { items, notizen, bezeichnung, fuer_benutzer_id, fuer_benutzer_name }); return r.data.data; }, updateRequest: async ( @@ -148,6 +136,7 @@ export const ausruestungsanfrageApi = { groesse?: string; kategorie?: string; eigenschaften?: Array<{ eigenschaft_id?: number; name: string; wert: string }>; + replacedItemIds?: string[]; }>, ): Promise => { await api.post(`/api/ausruestungsanfragen/requests/${anfrageId}/assign`, { assignments }); diff --git a/frontend/src/types/personalEquipment.types.ts b/frontend/src/types/personalEquipment.types.ts index a58b8f4..7177e03 100644 --- a/frontend/src/types/personalEquipment.types.ts +++ b/frontend/src/types/personalEquipment.types.ts @@ -22,6 +22,7 @@ export interface PersoenlicheAusruestung { inventarnummer?: string; anschaffung_datum?: string; zustand: string; + menge: number; notizen?: string; anfrage_id?: number; anfrage_position_id?: number; @@ -41,6 +42,7 @@ export interface CreatePersoenlicheAusruestungPayload { inventarnummer?: string; anschaffung_datum?: string; zustand?: string; + menge?: number; notizen?: string; eigenschaften?: { eigenschaft_id?: number; name: string; wert: string }[]; } @@ -56,6 +58,7 @@ export interface UpdatePersoenlicheAusruestungPayload { inventarnummer?: string | null; anschaffung_datum?: string | null; zustand?: string; + menge?: number | null; notizen?: string | null; eigenschaften?: { eigenschaft_id?: number | null; name: string; wert: string }[] | null; }