rework internal order system
This commit is contained in:
@@ -286,8 +286,8 @@ async function getRequests(filters?: { status?: string; anfrager_id?: string })
|
|||||||
const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
||||||
const result = await pool.query(
|
const result = await pool.query(
|
||||||
`SELECT a.*,
|
`SELECT a.*,
|
||||||
u.display_name AS anfrager_name,
|
COALESCE(u.given_name || ' ' || u.family_name, u.name) AS anfrager_name,
|
||||||
u2.display_name AS bearbeitet_von_name,
|
COALESCE(u2.given_name || ' ' || u2.family_name, u2.name) AS bearbeitet_von_name,
|
||||||
(SELECT COUNT(*)::int FROM ausruestung_anfrage_positionen p WHERE p.anfrage_id = a.id) AS positionen_count
|
(SELECT COUNT(*)::int FROM ausruestung_anfrage_positionen p WHERE p.anfrage_id = a.id) AS positionen_count
|
||||||
FROM ausruestung_anfragen a
|
FROM ausruestung_anfragen a
|
||||||
LEFT JOIN users u ON u.id = a.anfrager_id
|
LEFT JOIN users u ON u.id = a.anfrager_id
|
||||||
@@ -314,8 +314,8 @@ async function getMyRequests(userId: string) {
|
|||||||
async function getRequestById(id: number) {
|
async function getRequestById(id: number) {
|
||||||
const reqResult = await pool.query(
|
const reqResult = await pool.query(
|
||||||
`SELECT a.*,
|
`SELECT a.*,
|
||||||
u.display_name AS anfrager_name,
|
COALESCE(u.given_name || ' ' || u.family_name, u.name) AS anfrager_name,
|
||||||
u2.display_name AS bearbeitet_von_name
|
COALESCE(u2.given_name || ' ' || u2.family_name, u2.name) AS bearbeitet_von_name
|
||||||
FROM ausruestung_anfragen a
|
FROM ausruestung_anfragen a
|
||||||
LEFT JOIN users u ON u.id = a.anfrager_id
|
LEFT JOIN users u ON u.id = a.anfrager_id
|
||||||
LEFT JOIN users u2 ON u2.id = a.bearbeitet_von
|
LEFT JOIN users u2 ON u2.id = a.bearbeitet_von
|
||||||
|
|||||||
@@ -725,6 +725,10 @@ function KatalogTab() {
|
|||||||
queryFn: () => ausruestungsanfrageApi.getKategorien(),
|
queryFn: () => ausruestungsanfrageApi.getKategorien(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Split categories into top-level and children
|
||||||
|
const topKategorien = useMemo(() => kategorien.filter(k => !k.parent_id), [kategorien]);
|
||||||
|
const subKategorienOf = useCallback((parentId: number) => kategorien.filter(k => k.parent_id === parentId), [kategorien]);
|
||||||
|
|
||||||
// Build display names for hierarchical categories (e.g. "Kleidung > A-Uniform")
|
// Build display names for hierarchical categories (e.g. "Kleidung > A-Uniform")
|
||||||
const kategorieOptions = useMemo(() => {
|
const kategorieOptions = useMemo(() => {
|
||||||
const map = new Map(kategorien.map(k => [k.id, k]));
|
const map = new Map(kategorien.map(k => [k.id, k]));
|
||||||
@@ -738,6 +742,10 @@ function KatalogTab() {
|
|||||||
return kategorien.map(k => ({ id: k.id, name: getDisplayName(k), isChild: !!k.parent_id }));
|
return kategorien.map(k => ({ id: k.id, name: getDisplayName(k), isChild: !!k.parent_id }));
|
||||||
}, [kategorien]);
|
}, [kategorien]);
|
||||||
|
|
||||||
|
// For artikel dialog: track main + sub category separately
|
||||||
|
const [artikelMainKat, setArtikelMainKat] = useState<number | ''>('');
|
||||||
|
const artikelSubKats = useMemo(() => artikelMainKat ? subKategorienOf(artikelMainKat as number) : [], [artikelMainKat, subKategorienOf]);
|
||||||
|
|
||||||
const createItemMut = useMutation({
|
const createItemMut = useMutation({
|
||||||
mutationFn: (data: AusruestungArtikelFormData) => ausruestungsanfrageApi.createItem(data),
|
mutationFn: (data: AusruestungArtikelFormData) => ausruestungsanfrageApi.createItem(data),
|
||||||
onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['ausruestungsanfrage'] }); showSuccess('Artikel erstellt'); setArtikelDialogOpen(false); },
|
onSuccess: () => { queryClient.invalidateQueries({ queryKey: ['ausruestungsanfrage'] }); showSuccess('Artikel erstellt'); setArtikelDialogOpen(false); },
|
||||||
@@ -757,11 +765,19 @@ function KatalogTab() {
|
|||||||
const openNewArtikel = () => {
|
const openNewArtikel = () => {
|
||||||
setEditArtikel(null);
|
setEditArtikel(null);
|
||||||
setArtikelForm({ bezeichnung: '' });
|
setArtikelForm({ bezeichnung: '' });
|
||||||
|
setArtikelMainKat('');
|
||||||
setArtikelDialogOpen(true);
|
setArtikelDialogOpen(true);
|
||||||
};
|
};
|
||||||
const openEditArtikel = (a: AusruestungArtikel) => {
|
const openEditArtikel = (a: AusruestungArtikel) => {
|
||||||
setEditArtikel(a);
|
setEditArtikel(a);
|
||||||
setArtikelForm({ bezeichnung: a.bezeichnung, beschreibung: a.beschreibung, kategorie_id: a.kategorie_id ?? null });
|
setArtikelForm({ bezeichnung: a.bezeichnung, beschreibung: a.beschreibung, kategorie_id: a.kategorie_id ?? null });
|
||||||
|
// Determine main category (could be the item's category or its parent)
|
||||||
|
const kat = kategorien.find(k => k.id === a.kategorie_id);
|
||||||
|
if (kat?.parent_id) {
|
||||||
|
setArtikelMainKat(kat.parent_id);
|
||||||
|
} else {
|
||||||
|
setArtikelMainKat(a.kategorie_id || '');
|
||||||
|
}
|
||||||
setArtikelDialogOpen(true);
|
setArtikelDialogOpen(true);
|
||||||
};
|
};
|
||||||
const saveArtikel = () => {
|
const saveArtikel = () => {
|
||||||
@@ -846,14 +862,36 @@ function KatalogTab() {
|
|||||||
<TextField label="Beschreibung" multiline rows={2} value={artikelForm.beschreibung ?? ''} onChange={e => setArtikelForm(f => ({ ...f, beschreibung: e.target.value }))} />
|
<TextField label="Beschreibung" multiline rows={2} value={artikelForm.beschreibung ?? ''} onChange={e => setArtikelForm(f => ({ ...f, beschreibung: e.target.value }))} />
|
||||||
<TextField
|
<TextField
|
||||||
select
|
select
|
||||||
label="Kategorie"
|
label="Hauptkategorie"
|
||||||
value={artikelForm.kategorie_id ?? ''}
|
value={artikelMainKat}
|
||||||
onChange={e => setArtikelForm(f => ({ ...f, kategorie_id: e.target.value ? Number(e.target.value) : null }))}
|
onChange={e => {
|
||||||
|
const val = e.target.value ? Number(e.target.value) : '';
|
||||||
|
setArtikelMainKat(val);
|
||||||
|
// If no subcategories, set kategorie_id to main; otherwise clear it
|
||||||
|
if (val) {
|
||||||
|
const subs = subKategorienOf(val as number);
|
||||||
|
setArtikelForm(f => ({ ...f, kategorie_id: subs.length === 0 ? (val as number) : null }));
|
||||||
|
} else {
|
||||||
|
setArtikelForm(f => ({ ...f, kategorie_id: null }));
|
||||||
|
}
|
||||||
|
}}
|
||||||
fullWidth
|
fullWidth
|
||||||
>
|
>
|
||||||
<MenuItem value="">Keine</MenuItem>
|
<MenuItem value="">Keine</MenuItem>
|
||||||
{kategorieOptions.map(k => <MenuItem key={k.id} value={k.id}>{k.name}</MenuItem>)}
|
{topKategorien.map(k => <MenuItem key={k.id} value={k.id}>{k.name}</MenuItem>)}
|
||||||
</TextField>
|
</TextField>
|
||||||
|
{artikelMainKat && artikelSubKats.length > 0 && (
|
||||||
|
<TextField
|
||||||
|
select
|
||||||
|
label="Unterkategorie"
|
||||||
|
value={artikelForm.kategorie_id ?? ''}
|
||||||
|
onChange={e => setArtikelForm(f => ({ ...f, kategorie_id: e.target.value ? Number(e.target.value) : (artikelMainKat as number) }))}
|
||||||
|
fullWidth
|
||||||
|
>
|
||||||
|
<MenuItem value={artikelMainKat as number}>Keine (nur Hauptkategorie)</MenuItem>
|
||||||
|
{artikelSubKats.map(k => <MenuItem key={k.id} value={k.id}>{k.name}</MenuItem>)}
|
||||||
|
</TextField>
|
||||||
|
)}
|
||||||
{canManage && <EigenschaftenEditor artikelId={editArtikel?.id ?? null} />}
|
{canManage && <EigenschaftenEditor artikelId={editArtikel?.id ?? null} />}
|
||||||
</DialogContent>
|
</DialogContent>
|
||||||
<DialogActions>
|
<DialogActions>
|
||||||
|
|||||||
Reference in New Issue
Block a user