fix(bestellungen): automate delivery status transitions, enable received-qty input for creators, and add im_haus tracking to positionen

This commit is contained in:
Matthias Hochmeister
2026-04-17 11:42:12 +02:00
parent 7d2ea57c17
commit fcca04cc39
11 changed files with 367 additions and 108 deletions

View File

@@ -325,6 +325,7 @@ async function getRequests(filters?: { status?: string; anfrager_id?: string })
a.fuer_benutzer_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 AND p.geliefert) AS geliefert_count,
(SELECT COUNT(*)::int FROM ausruestung_anfrage_positionen p WHERE p.anfrage_id = a.id AND p.im_haus) AS im_haus_count,
EXISTS(
SELECT 1 FROM ausruestung_anfrage_bestellung ab
JOIN bestellungen b ON b.id = ab.bestellung_id
@@ -346,6 +347,7 @@ async function getMyRequests(userId: string) {
`SELECT a.*,
(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 AND p.geliefert) AS geliefert_count,
(SELECT COUNT(*)::int FROM ausruestung_anfrage_positionen p WHERE p.anfrage_id = a.id AND p.im_haus) AS im_haus_count,
EXISTS(
SELECT 1 FROM ausruestung_anfrage_bestellung ab
JOIN bestellungen b ON b.id = ab.bestellung_id
@@ -859,9 +861,9 @@ async function createOrdersFromRequest(
}
await client.query(
`INSERT INTO bestellpositionen (bestellung_id, bezeichnung, menge, einheit, notizen, artikel_id, spezifikationen)
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb)`,
[bestellung.id, pos.bezeichnung, pos.menge, pos.einheit || 'Stk', pos.notizen || null, artikelId, JSON.stringify(spezifikationen)]
`INSERT INTO bestellpositionen (bestellung_id, bezeichnung, menge, einheit, notizen, artikel_id, spezifikationen, anfrage_position_id)
VALUES ($1, $2, $3, $4, $5, $6, $7::jsonb, $8)`,
[bestellung.id, pos.bezeichnung, pos.menge, pos.einheit || 'Stk', pos.notizen || null, artikelId, JSON.stringify(spezifikationen), pos.position_id || null]
);
}

View File

@@ -41,6 +41,25 @@ async function getKatalogKategorien() {
}
}
// ---------------------------------------------------------------------------
// Members (all active users for member selector)
// ---------------------------------------------------------------------------
async function getAllMembers() {
try {
const result = await pool.query(
`SELECT id, COALESCE(given_name || ' ' || family_name, name) AS name
FROM users
WHERE is_active = true
ORDER BY name`,
);
return result.rows;
} catch (error) {
logger.error('BestellungService.getAllMembers failed', { error });
throw new Error('Mitglieder konnten nicht geladen werden');
}
}
// ---------------------------------------------------------------------------
// Vendors (Lieferanten)
// ---------------------------------------------------------------------------
@@ -574,6 +593,15 @@ async function updateReceivedQuantity(id: number, menge: number, userId: string)
const item = result.rows[0];
await logAction(item.bestellung_id, 'Liefermenge aktualisiert', `"${item.bezeichnung}": ${menge} von ${item.menge} erhalten`, userId);
// Sync im_haus on linked internal request position
if (item.anfrage_position_id) {
const imHaus = Number(item.erhalten_menge) >= Number(item.menge);
await pool.query(
`UPDATE ausruestung_anfrage_positionen SET im_haus = $1 WHERE id = $2`,
[imHaus, item.anfrage_position_id]
);
}
// Check if all items for this order are fully received
const allItems = await pool.query(
`SELECT menge, erhalten_menge FROM bestellpositionen WHERE bestellung_id = $1`,
@@ -760,6 +788,8 @@ async function getHistory(bestellungId: number) {
}
export default {
// Members
getAllMembers,
// Catalog
getKatalogItems,
getKatalogItem,