340 lines
13 KiB
JavaScript
340 lines
13 KiB
JavaScript
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' });
|
|
|
|
const asset = rows[0];
|
|
|
|
// Fetch sub-assets (children)
|
|
const [children] = await db.query('SELECT id, name, category, status, location FROM assets WHERE parent_id = ?', [req.params.id]);
|
|
asset.children = children;
|
|
|
|
// Fetch parent name if exists
|
|
if (asset.parent_id) {
|
|
const [parentRows] = await db.query('SELECT name FROM assets WHERE id = ?', [asset.parent_id]);
|
|
if (parentRows.length > 0) {
|
|
asset.parent_name = parentRows[0].name;
|
|
}
|
|
}
|
|
|
|
res.json(asset);
|
|
} catch (err) {
|
|
console.error(err);
|
|
res.status(500).json({ error: 'Database error' });
|
|
}
|
|
});
|
|
|
|
// Create Asset
|
|
router.post('/assets', async (req, res) => {
|
|
const { id, parent_id, name, category, model_name, serial_number, manufacturer, location, purchase_date, manager, status, specs, purchase_price, image_url, quantity } = req.body;
|
|
|
|
try {
|
|
const sql = `
|
|
INSERT INTO assets (id, parent_id, name, category, model_name, serial_number, manufacturer, location, purchase_date, manager, status, specs, purchase_price, image_url, quantity)
|
|
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
`;
|
|
await db.query(sql, [id, parent_id || null, name, category, model_name, serial_number, manufacturer, location, purchase_date, manager, status, specs, purchase_price, image_url, quantity || 1]);
|
|
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 { parent_id, name, category, model_name, serial_number, manufacturer, location, purchase_date, manager, status, specs, purchase_price, image_url, quantity } = req.body;
|
|
|
|
try {
|
|
const sql = `
|
|
UPDATE assets
|
|
SET parent_id=?, name=?, category=?, model_name=?, serial_number=?, manufacturer=?, location=?, purchase_date=?, manager=?, status=?, specs=?, purchase_price=?, image_url=?, quantity=?
|
|
WHERE id=?
|
|
`;
|
|
const [result] = await db.query(sql, [parent_id || null, name, category, model_name, serial_number, manufacturer, location, purchase_date, manager, status, specs, purchase_price, image_url, quantity || 1, 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' });
|
|
}
|
|
});
|
|
|
|
// ==========================================
|
|
// 4. Accessories
|
|
// ==========================================
|
|
|
|
// Get Accessories for an Asset
|
|
router.get('/assets/:asset_id/accessories', async (req, res) => {
|
|
try {
|
|
const [rows] = await db.query('SELECT * FROM asset_accessories WHERE asset_id = ? ORDER BY created_at ASC', [req.params.asset_id]);
|
|
res.json(rows);
|
|
} catch (err) {
|
|
console.error(err);
|
|
res.status(500).json({ error: 'Database error' });
|
|
}
|
|
});
|
|
|
|
// Add Accessory to Asset
|
|
router.post('/assets/:asset_id/accessories', async (req, res) => {
|
|
const { name, spec, quantity } = req.body;
|
|
const { asset_id } = req.params;
|
|
|
|
try {
|
|
const sql = `INSERT INTO asset_accessories (asset_id, name, spec, quantity) VALUES (?, ?, ?, ?)`;
|
|
const [result] = await db.query(sql, [asset_id, name, spec, quantity || 1]);
|
|
res.status(201).json({ message: 'Accessory added', id: result.insertId });
|
|
} catch (err) {
|
|
console.error(err);
|
|
res.status(500).json({ error: 'Database error' });
|
|
}
|
|
});
|
|
|
|
// Delete Accessory
|
|
router.delete('/accessories/:id', async (req, res) => {
|
|
try {
|
|
const [result] = await db.query('DELETE FROM asset_accessories WHERE id = ?', [req.params.id]);
|
|
if (result.affectedRows === 0) return res.status(404).json({ error: 'Accessory not found' });
|
|
res.json({ message: 'Accessory deleted' });
|
|
} catch (err) {
|
|
console.error(err);
|
|
res.status(500).json({ error: 'Database error' });
|
|
}
|
|
});
|
|
|
|
module.exports = router;
|