const express = require('express'); const router = express.Router(); const db = require('../../db'); const { hasRole } = require('../../middleware/authMiddleware'); // ========================================== // 1. Asset Management // ========================================== // Get All Assets router.get('/assets', async (req, res) => { try { const [rows] = await db.query('SELECT * FROM assets ORDER BY created_at DESC'); res.json(rows); } catch (err) { console.error(err); res.status(500).json({ error: 'Database error' }); } }); // Get Asset by ID router.get('/assets/:id', async (req, res) => { try { const [rows] = await db.query('SELECT * FROM assets WHERE id = ?', [req.params.id]); if (rows.length === 0) return res.status(404).json({ error: 'Asset not found' }); res.json(rows[0]); } catch (err) { console.error(err); res.status(500).json({ error: 'Database error' }); } }); // Create Asset router.post('/assets', async (req, res) => { const { id, name, category, model_name, serial_number, manufacturer, location, purchase_date, manager, status, specs, purchase_price, image_url } = req.body; try { const sql = ` INSERT INTO assets (id, name, category, model_name, serial_number, manufacturer, location, purchase_date, manager, status, specs, purchase_price, image_url) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) `; await db.query(sql, [id, name, category, model_name, serial_number, manufacturer, location, purchase_date, manager, status, specs, purchase_price, image_url]); res.status(201).json({ message: 'Asset created', id }); } catch (err) { console.error(err); res.status(500).json({ error: 'Database error' }); } }); // Update Asset router.put('/assets/:id', async (req, res) => { const { name, category, model_name, serial_number, manufacturer, location, purchase_date, manager, status, specs, purchase_price, image_url } = req.body; try { const sql = ` UPDATE assets SET name=?, category=?, model_name=?, serial_number=?, manufacturer=?, location=?, purchase_date=?, manager=?, status=?, specs=?, purchase_price=?, image_url=? WHERE id=? `; const [result] = await db.query(sql, [name, category, model_name, serial_number, manufacturer, location, purchase_date, manager, status, specs, purchase_price, image_url, req.params.id]); if (result.affectedRows === 0) return res.status(404).json({ error: 'Asset not found' }); res.json({ message: 'Asset updated' }); } catch (err) { console.error(err); res.status(500).json({ error: 'Database error' }); } }); // ========================================== // 2. Maintenance History // ========================================== // Get All Maintenance Records for an Asset router.get('/assets/:asset_id/maintenance', async (req, res) => { try { const [rows] = await db.query('SELECT * FROM maintenance_history WHERE asset_id = ? ORDER BY maintenance_date DESC', [req.params.asset_id]); res.json(rows); } catch (err) { console.error(err); res.status(500).json({ error: 'Database error' }); } }); // Get Single Maintenance Record by ID router.get('/maintenance/:id', async (req, res) => { try { const [rows] = await db.query('SELECT * FROM maintenance_history WHERE id = ?', [req.params.id]); if (rows.length === 0) return res.status(404).json({ error: 'Maintenance record not found' }); const record = rows[0]; // Fetch used parts const [parts] = await db.query(` SELECT mp.*, a.name as part_name, a.model_name FROM maintenance_parts mp JOIN assets a ON mp.part_id = a.id WHERE mp.maintenance_id = ? `, [record.id]); record.parts = parts; res.json(record); } catch (err) { console.error(err); res.status(500).json({ error: 'Database error' }); } }); // Create Maintenance Record router.post('/assets/:asset_id/maintenance', async (req, res) => { const { maintenance_date, type, content, images, parts } = req.body; // parts: [{ part_id, quantity }] const { asset_id } = req.params; const connection = await db.getConnection(); try { await connection.beginTransaction(); const sql = ` INSERT INTO maintenance_history (asset_id, maintenance_date, type, content, images) VALUES (?, ?, ?, ?, ?) `; const [result] = await connection.query(sql, [asset_id, maintenance_date, type, content, JSON.stringify(images || [])]); const maintenanceId = result.insertId; if (parts && Array.isArray(parts) && parts.length > 0) { for (const part of parts) { // 1. Deduct quantity from assets await connection.query('UPDATE assets SET quantity = quantity - ? WHERE id = ?', [part.quantity, part.part_id]); // 2. Add to maintenance_parts await connection.query( 'INSERT INTO maintenance_parts (maintenance_id, part_id, quantity) VALUES (?, ?, ?)', [maintenanceId, part.part_id, part.quantity] ); } } await connection.commit(); res.status(201).json({ message: 'Maintenance record created', id: maintenanceId }); } catch (err) { await connection.rollback(); console.error(err); res.status(500).json({ error: 'Database error' }); } finally { connection.release(); } }); // Update Maintenance Record router.put('/maintenance/:id', async (req, res) => { const { maintenance_date, type, content, images, parts } = req.body; const maintenanceId = req.params.id; const connection = await db.getConnection(); try { await connection.beginTransaction(); // 1. Update basic info const sql = ` UPDATE maintenance_history SET maintenance_date=?, type=?, content=?, images=? WHERE id=? `; const [result] = await connection.query(sql, [maintenance_date, type, content, JSON.stringify(images || []), maintenanceId]); if (result.affectedRows === 0) { await connection.rollback(); return res.status(404).json({ error: 'Maintenance record not found' }); } // 2. Handle Parts Update (Restore old -> Apply new) if (parts) { // Get existing parts to restore stock const [existingParts] = await connection.query('SELECT * FROM maintenance_parts WHERE maintenance_id = ?', [maintenanceId]); for (const part of existingParts) { await connection.query('UPDATE assets SET quantity = quantity + ? WHERE id = ?', [part.quantity, part.part_id]); } // Remove existing links await connection.query('DELETE FROM maintenance_parts WHERE maintenance_id = ?', [maintenanceId]); // Add new parts and deduct stock if (Array.isArray(parts) && parts.length > 0) { for (const part of parts) { await connection.query('UPDATE assets SET quantity = quantity - ? WHERE id = ?', [part.quantity, part.part_id]); await connection.query( 'INSERT INTO maintenance_parts (maintenance_id, part_id, quantity) VALUES (?, ?, ?)', [maintenanceId, part.part_id, part.quantity] ); } } } await connection.commit(); res.json({ message: 'Maintenance record updated' }); } catch (err) { await connection.rollback(); console.error(err); res.status(500).json({ error: 'Database error' }); } finally { connection.release(); } }); // Delete Maintenance Record router.delete('/maintenance/:id', async (req, res) => { const connection = await db.getConnection(); try { await connection.beginTransaction(); // 1. Restore stock for used parts const [usedParts] = await connection.query('SELECT * FROM maintenance_parts WHERE maintenance_id = ?', [req.params.id]); for (const part of usedParts) { await connection.query('UPDATE assets SET quantity = quantity + ? WHERE id = ?', [part.quantity, part.part_id]); } // 2. Delete record (Cascading delete will remove maintenance_parts rows, but we manually restored stock first) const [result] = await connection.query('DELETE FROM maintenance_history WHERE id = ?', [req.params.id]); if (result.affectedRows === 0) { await connection.rollback(); return res.status(404).json({ error: 'Maintenance record not found' }); } await connection.commit(); res.json({ message: 'Maintenance record deleted' }); } catch (err) { await connection.rollback(); console.error(err); res.status(500).json({ error: 'Database error' }); } finally { connection.release(); } }); // ========================================== // 3. Manuals // ========================================== // Get Manuals for an Asset router.get('/assets/:asset_id/manuals', async (req, res) => { try { const [rows] = await db.query('SELECT * FROM asset_manuals WHERE asset_id = ? ORDER BY created_at DESC', [req.params.asset_id]); res.json(rows); } catch (err) { console.error(err); res.status(500).json({ error: 'Database error' }); } }); // Add Manual to Asset router.post('/assets/:asset_id/manuals', async (req, res) => { const { file_name, file_url } = req.body; const { asset_id } = req.params; try { const sql = `INSERT INTO asset_manuals (asset_id, file_name, file_url) VALUES (?, ?, ?)`; const [result] = await db.query(sql, [asset_id, file_name, file_url]); res.status(201).json({ message: 'Manual added', id: result.insertId }); } catch (err) { console.error(err); res.status(500).json({ error: 'Database error' }); } }); // Delete Manual router.delete('/manuals/:id', async (req, res) => { try { const [result] = await db.query('DELETE FROM asset_manuals WHERE id = ?', [req.params.id]); if (result.affectedRows === 0) return res.status(404).json({ error: 'Manual not found' }); res.json({ message: 'Manual deleted' }); } catch (err) { console.error(err); res.status(500).json({ error: 'Database error' }); } }); module.exports = router;