Updated A LOT
This commit is contained in:
@@ -2,16 +2,20 @@ const express = require('express');
|
||||
const multer = require('multer');
|
||||
const { audit, now, one, run } = require('../db');
|
||||
const { annualSchedule } = require('../depreciation');
|
||||
const { requireRole } = require('../middleware/auth');
|
||||
const { requireCapability } = require('../middleware/auth');
|
||||
const {
|
||||
addAssetPhoto,
|
||||
createAsset,
|
||||
deleteAsset,
|
||||
deleteAssetPhoto,
|
||||
hydrateAsset,
|
||||
listAssets,
|
||||
lookupAssetByCode,
|
||||
massUpdateAssets,
|
||||
updateAsset
|
||||
updateAsset,
|
||||
updateAssetPhoto
|
||||
} = require('../services/assets');
|
||||
const { activeRuleSet } = require('../services/reports');
|
||||
const { ruleSetForBook } = require('../services/ruleSets');
|
||||
|
||||
const upload = multer({ storage: multer.memoryStorage(), limits: { fileSize: 16 * 1024 * 1024 } });
|
||||
const router = express.Router();
|
||||
@@ -20,28 +24,36 @@ router.get('/assets', (req, res) => {
|
||||
res.json({ assets: listAssets(req.query) });
|
||||
});
|
||||
|
||||
router.post('/assets', requireRole('admin', 'finance', 'operations'), (req, res) => {
|
||||
router.post('/assets', requireCapability('assets.edit'), (req, res) => {
|
||||
res.status(201).json({ asset: createAsset(req.body, req.user.id) });
|
||||
});
|
||||
|
||||
router.get('/assets/lookup', (req, res) => {
|
||||
const code = String(req.query.code || '').trim();
|
||||
if (!code) return res.status(400).json({ error: 'Scan code is required' });
|
||||
const asset = lookupAssetByCode(code);
|
||||
if (!asset) return res.status(404).json({ error: `No asset matches "${code}"` });
|
||||
return res.json({ asset });
|
||||
});
|
||||
|
||||
router.get('/assets/:id', (req, res) => {
|
||||
const asset = hydrateAsset(req.params.id);
|
||||
if (!asset) return res.status(404).json({ error: 'Asset not found' });
|
||||
return res.json({ asset });
|
||||
});
|
||||
|
||||
router.put('/assets/:id', requireRole('admin', 'finance', 'operations'), (req, res) => {
|
||||
router.put('/assets/:id', requireCapability('assets.edit'), (req, res) => {
|
||||
const asset = updateAsset(req.params.id, req.body, req.user.id);
|
||||
if (!asset) return res.status(404).json({ error: 'Asset not found' });
|
||||
return res.json({ asset });
|
||||
});
|
||||
|
||||
router.delete('/assets/:id', requireRole('admin', 'finance'), (req, res) => {
|
||||
router.delete('/assets/:id', requireCapability('assets.delete'), (req, res) => {
|
||||
if (!deleteAsset(req.params.id, req.user.id)) return res.status(404).json({ error: 'Asset not found' });
|
||||
return res.status(204).end();
|
||||
});
|
||||
|
||||
router.post('/assets/mass-update', requireRole('admin', 'finance'), (req, res) => {
|
||||
router.post('/assets/mass-update', requireCapability('assets.bulk'), (req, res) => {
|
||||
const ids = Array.isArray(req.body.ids) ? req.body.ids : [];
|
||||
const updated = massUpdateAssets(ids, req.body.changes || {}, req.user.id);
|
||||
if (!updated) return res.status(400).json({ error: 'Choose assets and editable fields' });
|
||||
@@ -51,16 +63,15 @@ router.post('/assets/mass-update', requireRole('admin', 'finance'), (req, res) =
|
||||
router.get('/assets/:id/depreciation', (req, res) => {
|
||||
const asset = hydrateAsset(req.params.id);
|
||||
if (!asset) return res.status(404).json({ error: 'Asset not found' });
|
||||
const rules = activeRuleSet();
|
||||
const startYear = Number(req.query.startYear || new Date().getFullYear());
|
||||
const endYear = Number(req.query.endYear || startYear + 5);
|
||||
const schedules = asset.books
|
||||
.filter((book) => book.active)
|
||||
.flatMap((book) => annualSchedule(asset, book, rules, { startYear, endYear }));
|
||||
.flatMap((book) => annualSchedule(asset, book, ruleSetForBook(book.book_type), { startYear, endYear }));
|
||||
res.json({ assetId: asset.asset_id, schedules });
|
||||
});
|
||||
|
||||
router.post('/assets/:id/files', upload.single('file'), requireRole('admin', 'finance', 'operations'), (req, res) => {
|
||||
router.post('/assets/:id/files', upload.single('file'), requireCapability('assets.edit'), (req, res) => {
|
||||
if (!req.file) return res.status(400).json({ error: 'File is required' });
|
||||
const result = run(
|
||||
'INSERT INTO asset_files (asset_id, file_name, mime_type, size, content_base64, uploaded_by, uploaded_at) VALUES (?, ?, ?, ?, ?, ?, ?)',
|
||||
@@ -78,14 +89,32 @@ router.get('/assets/:id/files/:fileId', (req, res) => {
|
||||
return res.send(Buffer.from(file.content_base64, 'base64'));
|
||||
});
|
||||
|
||||
router.delete('/assets/:id/files/:fileId', requireRole('admin', 'finance', 'operations'), (req, res) => {
|
||||
router.delete('/assets/:id/files/:fileId', requireCapability('assets.edit'), (req, res) => {
|
||||
const result = run('DELETE FROM asset_files WHERE id = ? AND asset_id = ?', [req.params.fileId, req.params.id]);
|
||||
if (!result.changes) return res.status(404).json({ error: 'File not found' });
|
||||
audit(req.user.id, 'delete', 'asset_file', req.params.fileId, null, { asset_id: req.params.id });
|
||||
return res.status(204).end();
|
||||
});
|
||||
|
||||
router.post('/assets/:id/warranties', requireRole('admin', 'finance', 'operations'), (req, res) => {
|
||||
// Identification photos (base64 data URLs, with optional captions)
|
||||
router.post('/assets/:id/photos', requireCapability('assets.edit'), (req, res) => {
|
||||
const photo = addAssetPhoto(req.params.id, req.body, req.user.id);
|
||||
if (!photo) return res.status(404).json({ error: 'Asset not found' });
|
||||
return res.status(201).json({ photo });
|
||||
});
|
||||
|
||||
router.put('/assets/:id/photos/:photoId', requireCapability('assets.edit'), (req, res) => {
|
||||
const photo = updateAssetPhoto(req.params.id, req.params.photoId, req.body, req.user.id);
|
||||
if (!photo) return res.status(404).json({ error: 'Photo not found' });
|
||||
return res.json({ photo });
|
||||
});
|
||||
|
||||
router.delete('/assets/:id/photos/:photoId', requireCapability('assets.edit'), (req, res) => {
|
||||
if (!deleteAssetPhoto(req.params.id, req.params.photoId, req.user.id)) return res.status(404).json({ error: 'Photo not found' });
|
||||
return res.status(204).end();
|
||||
});
|
||||
|
||||
router.post('/assets/:id/warranties', requireCapability('assets.edit'), (req, res) => {
|
||||
const b = req.body;
|
||||
const result = run(
|
||||
`INSERT INTO warranties (
|
||||
@@ -107,14 +136,14 @@ router.post('/assets/:id/warranties', requireRole('admin', 'finance', 'operation
|
||||
});
|
||||
});
|
||||
|
||||
router.delete('/assets/:id/warranties/:warrantyId', requireRole('admin', 'finance', 'operations'), (req, res) => {
|
||||
router.delete('/assets/:id/warranties/:warrantyId', requireCapability('assets.edit'), (req, res) => {
|
||||
const result = run('DELETE FROM warranties WHERE id = ? AND asset_id = ?', [req.params.warrantyId, req.params.id]);
|
||||
if (!result.changes) return res.status(404).json({ error: 'Warranty not found' });
|
||||
audit(req.user.id, 'delete', 'warranty', req.params.warrantyId, null, { asset_id: req.params.id });
|
||||
return res.status(204).end();
|
||||
});
|
||||
|
||||
router.post('/assets/:id/tasks', requireRole('admin', 'finance', 'operations'), (req, res) => {
|
||||
router.post('/assets/:id/tasks', requireCapability('assets.edit'), (req, res) => {
|
||||
const created = now();
|
||||
const result = run(
|
||||
'INSERT INTO tasks (asset_id, title, type, status, due_date, assigned_to, notes, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
@@ -124,7 +153,7 @@ router.post('/assets/:id/tasks', requireRole('admin', 'finance', 'operations'),
|
||||
res.status(201).json({ task: one('SELECT * FROM tasks WHERE id = ?', [result.lastInsertRowid]) });
|
||||
});
|
||||
|
||||
router.put('/assets/:id/tasks/:taskId', requireRole('admin', 'finance', 'operations'), (req, res) => {
|
||||
router.put('/assets/:id/tasks/:taskId', requireCapability('assets.edit'), (req, res) => {
|
||||
const before = one('SELECT * FROM tasks WHERE id = ? AND asset_id = ?', [req.params.taskId, req.params.id]);
|
||||
if (!before) return res.status(404).json({ error: 'Task not found' });
|
||||
run(
|
||||
@@ -143,14 +172,14 @@ router.put('/assets/:id/tasks/:taskId', requireRole('admin', 'finance', 'operati
|
||||
return res.json({ task: one('SELECT * FROM tasks WHERE id = ?', [req.params.taskId]) });
|
||||
});
|
||||
|
||||
router.delete('/assets/:id/tasks/:taskId', requireRole('admin', 'finance', 'operations'), (req, res) => {
|
||||
router.delete('/assets/:id/tasks/:taskId', requireCapability('assets.edit'), (req, res) => {
|
||||
const result = run('DELETE FROM tasks WHERE id = ? AND asset_id = ?', [req.params.taskId, req.params.id]);
|
||||
if (!result.changes) return res.status(404).json({ error: 'Task not found' });
|
||||
audit(req.user.id, 'delete', 'task', req.params.taskId, null, { asset_id: req.params.id });
|
||||
return res.status(204).end();
|
||||
});
|
||||
|
||||
router.post('/assets/:id/notes', requireRole('admin', 'finance', 'operations'), (req, res) => {
|
||||
router.post('/assets/:id/notes', requireCapability('assets.edit'), (req, res) => {
|
||||
if (!req.body.body) return res.status(400).json({ error: 'Note body is required' });
|
||||
const result = run(
|
||||
'INSERT INTO asset_notes (asset_id, body, created_by, created_at) VALUES (?, ?, ?, ?)',
|
||||
@@ -165,7 +194,7 @@ router.post('/assets/:id/notes', requireRole('admin', 'finance', 'operations'),
|
||||
});
|
||||
});
|
||||
|
||||
router.delete('/assets/:id/notes/:noteId', requireRole('admin', 'finance', 'operations'), (req, res) => {
|
||||
router.delete('/assets/:id/notes/:noteId', requireCapability('assets.edit'), (req, res) => {
|
||||
const result = run('DELETE FROM asset_notes WHERE id = ? AND asset_id = ?', [req.params.noteId, req.params.id]);
|
||||
if (!result.changes) return res.status(404).json({ error: 'Note not found' });
|
||||
audit(req.user.id, 'delete', 'asset_note', req.params.noteId, null, { asset_id: req.params.id });
|
||||
|
||||
Reference in New Issue
Block a user