refactor external orders
This commit is contained in:
@@ -21,6 +21,40 @@ class BestellungController {
|
||||
}
|
||||
}
|
||||
|
||||
async getVendor(req: Request, res: Response): Promise<void> {
|
||||
const id = parseInt(param(req, 'id'), 10);
|
||||
if (isNaN(id)) {
|
||||
res.status(400).json({ success: false, message: 'Ungültige ID' });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const vendor = await bestellungService.getVendorById(id);
|
||||
if (!vendor) {
|
||||
res.status(404).json({ success: false, message: 'Lieferant nicht gefunden' });
|
||||
return;
|
||||
}
|
||||
res.status(200).json({ success: true, data: vendor });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.getVendor error', { error });
|
||||
res.status(500).json({ success: false, message: 'Lieferant konnte nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async getVendorOrders(req: Request, res: Response): Promise<void> {
|
||||
const id = parseInt(param(req, 'id'), 10);
|
||||
if (isNaN(id)) {
|
||||
res.status(400).json({ success: false, message: 'Ungültige ID' });
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const orders = await bestellungService.getOrders({ lieferant_id: id });
|
||||
res.status(200).json({ success: true, data: orders });
|
||||
} catch (error) {
|
||||
logger.error('BestellungController.getVendorOrders error', { error });
|
||||
res.status(500).json({ success: false, message: 'Bestellungen konnten nicht geladen werden' });
|
||||
}
|
||||
}
|
||||
|
||||
async createVendor(req: Request, res: Response): Promise<void> {
|
||||
const { name } = req.body;
|
||||
if (!name || typeof name !== 'string' || name.trim().length === 0) {
|
||||
|
||||
14
backend/src/database/migrations/061_add_laufende_nummer.sql
Normal file
14
backend/src/database/migrations/061_add_laufende_nummer.sql
Normal file
@@ -0,0 +1,14 @@
|
||||
-- Add laufende_nummer (sequential number per year) to bestellungen
|
||||
ALTER TABLE bestellungen ADD COLUMN laufende_nummer INTEGER;
|
||||
|
||||
-- Backfill existing rows with sequential numbers per year
|
||||
WITH numbered AS (
|
||||
SELECT id, ROW_NUMBER() OVER (
|
||||
PARTITION BY EXTRACT(YEAR FROM erstellt_am) ORDER BY erstellt_am, id
|
||||
) AS nr
|
||||
FROM bestellungen
|
||||
)
|
||||
UPDATE bestellungen b SET laufende_nummer = n.nr FROM numbered n WHERE b.id = n.id;
|
||||
|
||||
-- Make NOT NULL after backfill
|
||||
ALTER TABLE bestellungen ALTER COLUMN laufende_nummer SET NOT NULL;
|
||||
@@ -17,6 +17,20 @@ router.get(
|
||||
bestellungController.listVendors.bind(bestellungController)
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/vendors/:id',
|
||||
authenticate,
|
||||
requirePermission('bestellungen:view'),
|
||||
bestellungController.getVendor.bind(bestellungController)
|
||||
);
|
||||
|
||||
router.get(
|
||||
'/vendors/:id/orders',
|
||||
authenticate,
|
||||
requirePermission('bestellungen:view'),
|
||||
bestellungController.getVendorOrders.bind(bestellungController)
|
||||
);
|
||||
|
||||
router.post(
|
||||
'/vendors',
|
||||
authenticate,
|
||||
|
||||
@@ -119,13 +119,17 @@ async function getOrders(filters?: { status?: string; lieferant_id?: number; bes
|
||||
l.name AS lieferant_name,
|
||||
COALESCE(u.name, u.preferred_username, u.email) AS besteller_name,
|
||||
COALESCE(pos.total_cost, 0) AS total_cost,
|
||||
COALESCE(pos.items_count, 0) AS items_count
|
||||
COALESCE(pos.items_count, 0) AS items_count,
|
||||
COALESCE(pos.total_received, 0) AS total_received,
|
||||
COALESCE(pos.total_ordered, 0) AS total_ordered
|
||||
FROM bestellungen b
|
||||
LEFT JOIN lieferanten l ON l.id = b.lieferant_id
|
||||
LEFT JOIN users u ON u.id = b.erstellt_von
|
||||
LEFT JOIN LATERAL (
|
||||
SELECT SUM(einzelpreis * menge) AS total_cost,
|
||||
COUNT(*) AS items_count
|
||||
COUNT(*) AS items_count,
|
||||
SUM(erhalten_menge) AS total_received,
|
||||
SUM(menge) AS total_ordered
|
||||
FROM bestellpositionen
|
||||
WHERE bestellung_id = b.id
|
||||
) pos ON true
|
||||
@@ -178,12 +182,21 @@ async function createOrder(data: { bezeichnung: string; lieferant_id?: number; b
|
||||
const client = await pool.connect();
|
||||
try {
|
||||
await client.query('BEGIN');
|
||||
|
||||
// Get next laufende_nummer for the current year
|
||||
const nrResult = await client.query(
|
||||
`SELECT COALESCE(MAX(laufende_nummer), 0) + 1 AS next_nr
|
||||
FROM bestellungen
|
||||
WHERE EXTRACT(YEAR FROM erstellt_am) = EXTRACT(YEAR FROM NOW())`
|
||||
);
|
||||
const laufendeNummer = nrResult.rows[0].next_nr;
|
||||
|
||||
const bestellerId = data.besteller_id && data.besteller_id.trim() ? data.besteller_id.trim() : null;
|
||||
const result = await client.query(
|
||||
`INSERT INTO bestellungen (bezeichnung, lieferant_id, besteller_id, notizen, budget, steuersatz, erstellt_von)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
`INSERT INTO bestellungen (bezeichnung, lieferant_id, besteller_id, notizen, budget, steuersatz, laufende_nummer, erstellt_von)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
RETURNING *`,
|
||||
[data.bezeichnung, data.lieferant_id || null, bestellerId, data.notizen || null, data.budget || null, data.steuersatz ?? 20, userId]
|
||||
[data.bezeichnung, data.lieferant_id || null, bestellerId, data.notizen || null, data.budget || null, data.steuersatz ?? 20, laufendeNummer, userId]
|
||||
);
|
||||
const order = result.rows[0];
|
||||
|
||||
|
||||
Reference in New Issue
Block a user