npms-exam-kit 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/exam-kit.js +357 -0
- package/package.json +25 -0
- package/projects/CRPMS-main/backend-project/config/db.js +12 -0
- package/projects/CRPMS-main/backend-project/config/initDb.js +92 -0
- package/projects/CRPMS-main/backend-project/middleware/auth.js +8 -0
- package/projects/CRPMS-main/backend-project/package-lock.json +1429 -0
- package/projects/CRPMS-main/backend-project/package.json +21 -0
- package/projects/CRPMS-main/backend-project/routes/auth.js +26 -0
- package/projects/CRPMS-main/backend-project/routes/cars.js +36 -0
- package/projects/CRPMS-main/backend-project/routes/payments.js +69 -0
- package/projects/CRPMS-main/backend-project/routes/reports.js +58 -0
- package/projects/CRPMS-main/backend-project/routes/serviceRecords.js +91 -0
- package/projects/CRPMS-main/backend-project/routes/services.js +36 -0
- package/projects/CRPMS-main/backend-project/server.js +44 -0
- package/projects/CRPMS-main/database.sql +59 -0
- package/projects/CRPMS-main/frontend-project/README.md +16 -0
- package/projects/CRPMS-main/frontend-project/eslint.config.js +21 -0
- package/projects/CRPMS-main/frontend-project/index.html +13 -0
- package/projects/CRPMS-main/frontend-project/package-lock.json +3356 -0
- package/projects/CRPMS-main/frontend-project/package.json +32 -0
- package/projects/CRPMS-main/frontend-project/public/favicon.svg +1 -0
- package/projects/CRPMS-main/frontend-project/public/icons.svg +24 -0
- package/projects/CRPMS-main/frontend-project/src/App.css +184 -0
- package/projects/CRPMS-main/frontend-project/src/App.jsx +72 -0
- package/projects/CRPMS-main/frontend-project/src/api/axios.js +8 -0
- package/projects/CRPMS-main/frontend-project/src/assets/hero.png +0 -0
- package/projects/CRPMS-main/frontend-project/src/assets/react.svg +1 -0
- package/projects/CRPMS-main/frontend-project/src/assets/vite.svg +1 -0
- package/projects/CRPMS-main/frontend-project/src/components/Navbar.jsx +54 -0
- package/projects/CRPMS-main/frontend-project/src/components/ProtectedRoute.jsx +9 -0
- package/projects/CRPMS-main/frontend-project/src/context/AuthContext.jsx +35 -0
- package/projects/CRPMS-main/frontend-project/src/index.css +14 -0
- package/projects/CRPMS-main/frontend-project/src/main.jsx +10 -0
- package/projects/CRPMS-main/frontend-project/src/pages/Bill.jsx +227 -0
- package/projects/CRPMS-main/frontend-project/src/pages/Cars.jsx +112 -0
- package/projects/CRPMS-main/frontend-project/src/pages/Login.jsx +78 -0
- package/projects/CRPMS-main/frontend-project/src/pages/Payments.jsx +153 -0
- package/projects/CRPMS-main/frontend-project/src/pages/Reports.jsx +199 -0
- package/projects/CRPMS-main/frontend-project/src/pages/ServiceRecords.jsx +182 -0
- package/projects/CRPMS-main/frontend-project/src/pages/Services.jsx +125 -0
- package/projects/CRPMS-main/frontend-project/vite.config.js +10 -0
- package/projects/SIMS-master/backend-project/.env.example +6 -0
- package/projects/SIMS-master/backend-project/config/db.js +12 -0
- package/projects/SIMS-master/backend-project/middleware/auth.js +8 -0
- package/projects/SIMS-master/backend-project/package-lock.json +1221 -0
- package/projects/SIMS-master/backend-project/package.json +23 -0
- package/projects/SIMS-master/backend-project/routes/auth.js +29 -0
- package/projects/SIMS-master/backend-project/routes/reports.js +51 -0
- package/projects/SIMS-master/backend-project/routes/spareParts.js +34 -0
- package/projects/SIMS-master/backend-project/routes/stockIn.js +53 -0
- package/projects/SIMS-master/backend-project/routes/stockOut.js +146 -0
- package/projects/SIMS-master/backend-project/seed.js +20 -0
- package/projects/SIMS-master/backend-project/server.js +43 -0
- package/projects/SIMS-master/database.sql +43 -0
- package/projects/SIMS-master/frontend-project/index.html +12 -0
- package/projects/SIMS-master/frontend-project/package-lock.json +3352 -0
- package/projects/SIMS-master/frontend-project/package.json +27 -0
- package/projects/SIMS-master/frontend-project/postcss.config.js +6 -0
- package/projects/SIMS-master/frontend-project/src/App.jsx +53 -0
- package/projects/SIMS-master/frontend-project/src/components/Navbar.jsx +103 -0
- package/projects/SIMS-master/frontend-project/src/index.css +3 -0
- package/projects/SIMS-master/frontend-project/src/main.jsx +10 -0
- package/projects/SIMS-master/frontend-project/src/pages/Login.jsx +92 -0
- package/projects/SIMS-master/frontend-project/src/pages/Reports.jsx +279 -0
- package/projects/SIMS-master/frontend-project/src/pages/SparePart.jsx +185 -0
- package/projects/SIMS-master/frontend-project/src/pages/StockIn.jsx +170 -0
- package/projects/SIMS-master/frontend-project/src/pages/StockOut.jsx +288 -0
- package/projects/SIMS-master/frontend-project/tailwind.config.js +11 -0
- package/projects/SIMS-master/frontend-project/vite.config.js +9 -0
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "backend-project",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "SmartPark SIMS Backend",
|
|
5
|
+
"main": "server.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "node server.js",
|
|
8
|
+
"dev": "nodemon server.js",
|
|
9
|
+
"seed": "node seed.js"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"bcryptjs": "^2.4.3",
|
|
13
|
+
"body-parser": "^1.20.2",
|
|
14
|
+
"cors": "^2.8.5",
|
|
15
|
+
"dotenv": "^16.3.1",
|
|
16
|
+
"express": "^4.18.2",
|
|
17
|
+
"express-session": "^1.17.3",
|
|
18
|
+
"mysql2": "^3.6.5"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"nodemon": "^3.0.2"
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const router = express.Router();
|
|
3
|
+
|
|
4
|
+
router.post('/login', (req, res) => {
|
|
5
|
+
const { username, password } = req.body;
|
|
6
|
+
if (!username || !password) {
|
|
7
|
+
return res.status(400).json({ message: 'Username and password are required' });
|
|
8
|
+
}
|
|
9
|
+
req.session.user = { id: 1, username };
|
|
10
|
+
res.json({ message: 'Login successful', username });
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
router.post('/logout', (req, res) => {
|
|
14
|
+
req.session.destroy((err) => {
|
|
15
|
+
if (err) return res.status(500).json({ message: 'Logout failed' });
|
|
16
|
+
res.clearCookie('connect.sid');
|
|
17
|
+
res.json({ message: 'Logged out successfully' });
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
router.get('/check', (req, res) => {
|
|
22
|
+
if (req.session && req.session.user) {
|
|
23
|
+
res.json({ authenticated: true, username: req.session.user.username });
|
|
24
|
+
} else {
|
|
25
|
+
res.json({ authenticated: false });
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
module.exports = router;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const router = express.Router();
|
|
3
|
+
const db = require('../config/db');
|
|
4
|
+
const requireAuth = require('../middleware/auth');
|
|
5
|
+
|
|
6
|
+
// Daily StockOut Report
|
|
7
|
+
router.get('/daily-stockout', requireAuth, async (req, res) => {
|
|
8
|
+
const { date } = req.query;
|
|
9
|
+
const reportDate = date || new Date().toISOString().split('T')[0];
|
|
10
|
+
try {
|
|
11
|
+
const [rows] = await db.query(`
|
|
12
|
+
SELECT so.StockOutID, sp.Name AS SparepartName, sp.Category,
|
|
13
|
+
so.StockOutQuantity, so.StockOutUnitPrice, so.StockOutTotalPrice, so.StockOutDate
|
|
14
|
+
FROM Stock_Out so
|
|
15
|
+
JOIN Spare_Part sp ON so.SparePartID = sp.SparePartID
|
|
16
|
+
WHERE DATE(so.StockOutDate) = ?
|
|
17
|
+
ORDER BY so.StockOutID DESC
|
|
18
|
+
`, [reportDate]);
|
|
19
|
+
res.json(rows);
|
|
20
|
+
} catch (err) {
|
|
21
|
+
console.error(err);
|
|
22
|
+
res.status(500).json({ message: 'Server error' });
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// Daily Stock Status Report
|
|
27
|
+
router.get('/stock-status', requireAuth, async (req, res) => {
|
|
28
|
+
const { date } = req.query;
|
|
29
|
+
const reportDate = date || new Date().toISOString().split('T')[0];
|
|
30
|
+
try {
|
|
31
|
+
const [rows] = await db.query(`
|
|
32
|
+
SELECT
|
|
33
|
+
sp.SparePartID,
|
|
34
|
+
sp.Name AS SparepartName,
|
|
35
|
+
sp.Category,
|
|
36
|
+
sp.Quantity + COALESCE(SUM(CASE WHEN DATE(so.StockOutDate) = ? THEN so.StockOutQuantity ELSE 0 END), 0) AS StoredQuantity,
|
|
37
|
+
COALESCE(SUM(CASE WHEN DATE(so.StockOutDate) = ? THEN so.StockOutQuantity ELSE 0 END), 0) AS DailyStockOut,
|
|
38
|
+
sp.Quantity AS RemainingQuantity
|
|
39
|
+
FROM Spare_Part sp
|
|
40
|
+
LEFT JOIN Stock_Out so ON sp.SparePartID = so.SparePartID
|
|
41
|
+
GROUP BY sp.SparePartID, sp.Name, sp.Category, sp.Quantity
|
|
42
|
+
ORDER BY sp.Name
|
|
43
|
+
`, [reportDate, reportDate]);
|
|
44
|
+
res.json(rows);
|
|
45
|
+
} catch (err) {
|
|
46
|
+
console.error(err);
|
|
47
|
+
res.status(500).json({ message: 'Server error' });
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
module.exports = router;
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const router = express.Router();
|
|
3
|
+
const db = require('../config/db');
|
|
4
|
+
const requireAuth = require('../middleware/auth');
|
|
5
|
+
|
|
6
|
+
router.get('/', requireAuth, async (req, res) => {
|
|
7
|
+
try {
|
|
8
|
+
const [rows] = await db.query('SELECT * FROM Spare_Part ORDER BY CreatedAt DESC');
|
|
9
|
+
res.json(rows);
|
|
10
|
+
} catch (err) {
|
|
11
|
+
console.error(err);
|
|
12
|
+
res.status(500).json({ message: 'Server error' });
|
|
13
|
+
}
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
router.post('/', requireAuth, async (req, res) => {
|
|
17
|
+
const { Name, Category, Quantity, UnitPrice } = req.body;
|
|
18
|
+
if (!Name || !Category || !Quantity || !UnitPrice) {
|
|
19
|
+
return res.status(400).json({ message: 'All fields are required' });
|
|
20
|
+
}
|
|
21
|
+
const TotalPrice = parseFloat(Quantity) * parseFloat(UnitPrice);
|
|
22
|
+
try {
|
|
23
|
+
const [result] = await db.query(
|
|
24
|
+
'INSERT INTO Spare_Part (Name, Category, Quantity, UnitPrice, TotalPrice) VALUES (?, ?, ?, ?, ?)',
|
|
25
|
+
[Name, Category, parseInt(Quantity), parseFloat(UnitPrice), TotalPrice]
|
|
26
|
+
);
|
|
27
|
+
res.status(201).json({ message: 'Spare part added successfully', id: result.insertId });
|
|
28
|
+
} catch (err) {
|
|
29
|
+
console.error(err);
|
|
30
|
+
res.status(500).json({ message: 'Server error' });
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
module.exports = router;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const router = express.Router();
|
|
3
|
+
const db = require('../config/db');
|
|
4
|
+
const requireAuth = require('../middleware/auth');
|
|
5
|
+
|
|
6
|
+
router.get('/', requireAuth, async (req, res) => {
|
|
7
|
+
try {
|
|
8
|
+
const [rows] = await db.query(`
|
|
9
|
+
SELECT si.StockInID, si.SparePartID, si.StockInQuantity, si.StockInDate,
|
|
10
|
+
sp.Name AS SparepartName, sp.Category
|
|
11
|
+
FROM Stock_In si
|
|
12
|
+
JOIN Spare_Part sp ON si.SparePartID = sp.SparePartID
|
|
13
|
+
ORDER BY si.StockInDate DESC, si.StockInID DESC
|
|
14
|
+
`);
|
|
15
|
+
res.json(rows);
|
|
16
|
+
} catch (err) {
|
|
17
|
+
console.error(err);
|
|
18
|
+
res.status(500).json({ message: 'Server error' });
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
router.post('/', requireAuth, async (req, res) => {
|
|
23
|
+
const { SparePartID, StockInQuantity, StockInDate } = req.body;
|
|
24
|
+
if (!SparePartID || !StockInQuantity || !StockInDate) {
|
|
25
|
+
return res.status(400).json({ message: 'All fields are required' });
|
|
26
|
+
}
|
|
27
|
+
const conn = await db.getConnection();
|
|
28
|
+
try {
|
|
29
|
+
await conn.beginTransaction();
|
|
30
|
+
await conn.query(
|
|
31
|
+
'INSERT INTO Stock_In (SparePartID, StockInQuantity, StockInDate) VALUES (?, ?, ?)',
|
|
32
|
+
[SparePartID, parseInt(StockInQuantity), StockInDate]
|
|
33
|
+
);
|
|
34
|
+
await conn.query(
|
|
35
|
+
'UPDATE Spare_Part SET Quantity = Quantity + ? WHERE SparePartID = ?',
|
|
36
|
+
[parseInt(StockInQuantity), SparePartID]
|
|
37
|
+
);
|
|
38
|
+
await conn.query(
|
|
39
|
+
'UPDATE Spare_Part SET TotalPrice = Quantity * UnitPrice WHERE SparePartID = ?',
|
|
40
|
+
[SparePartID]
|
|
41
|
+
);
|
|
42
|
+
await conn.commit();
|
|
43
|
+
res.status(201).json({ message: 'Stock in recorded successfully' });
|
|
44
|
+
} catch (err) {
|
|
45
|
+
await conn.rollback();
|
|
46
|
+
console.error(err);
|
|
47
|
+
res.status(500).json({ message: 'Server error' });
|
|
48
|
+
} finally {
|
|
49
|
+
conn.release();
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
module.exports = router;
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const router = express.Router();
|
|
3
|
+
const db = require('../config/db');
|
|
4
|
+
const requireAuth = require('../middleware/auth');
|
|
5
|
+
|
|
6
|
+
router.get('/', requireAuth, async (req, res) => {
|
|
7
|
+
try {
|
|
8
|
+
const [rows] = await db.query(`
|
|
9
|
+
SELECT so.StockOutID, so.SparePartID, so.StockOutQuantity,
|
|
10
|
+
so.StockOutUnitPrice, so.StockOutTotalPrice, so.StockOutDate,
|
|
11
|
+
sp.Name AS SparepartName, sp.Category
|
|
12
|
+
FROM Stock_Out so
|
|
13
|
+
JOIN Spare_Part sp ON so.SparePartID = sp.SparePartID
|
|
14
|
+
ORDER BY so.StockOutDate DESC, so.StockOutID DESC
|
|
15
|
+
`);
|
|
16
|
+
res.json(rows);
|
|
17
|
+
} catch (err) {
|
|
18
|
+
console.error(err);
|
|
19
|
+
res.status(500).json({ message: 'Server error' });
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
router.post('/', requireAuth, async (req, res) => {
|
|
24
|
+
const { SparePartID, StockOutQuantity, StockOutUnitPrice, StockOutDate } = req.body;
|
|
25
|
+
if (!SparePartID || !StockOutQuantity || !StockOutUnitPrice || !StockOutDate) {
|
|
26
|
+
return res.status(400).json({ message: 'All fields are required' });
|
|
27
|
+
}
|
|
28
|
+
const StockOutTotalPrice = parseFloat(StockOutQuantity) * parseFloat(StockOutUnitPrice);
|
|
29
|
+
const conn = await db.getConnection();
|
|
30
|
+
try {
|
|
31
|
+
await conn.beginTransaction();
|
|
32
|
+
const [parts] = await conn.query('SELECT Quantity FROM Spare_Part WHERE SparePartID = ?', [SparePartID]);
|
|
33
|
+
if (parts.length === 0) {
|
|
34
|
+
await conn.rollback();
|
|
35
|
+
return res.status(404).json({ message: 'Spare part not found' });
|
|
36
|
+
}
|
|
37
|
+
if (parts[0].Quantity < parseInt(StockOutQuantity)) {
|
|
38
|
+
await conn.rollback();
|
|
39
|
+
return res.status(400).json({ message: `Insufficient stock. Available: ${parts[0].Quantity}` });
|
|
40
|
+
}
|
|
41
|
+
await conn.query(
|
|
42
|
+
'INSERT INTO Stock_Out (SparePartID, StockOutQuantity, StockOutUnitPrice, StockOutTotalPrice, StockOutDate) VALUES (?, ?, ?, ?, ?)',
|
|
43
|
+
[SparePartID, parseInt(StockOutQuantity), parseFloat(StockOutUnitPrice), StockOutTotalPrice, StockOutDate]
|
|
44
|
+
);
|
|
45
|
+
await conn.query(
|
|
46
|
+
'UPDATE Spare_Part SET Quantity = Quantity - ? WHERE SparePartID = ?',
|
|
47
|
+
[parseInt(StockOutQuantity), SparePartID]
|
|
48
|
+
);
|
|
49
|
+
await conn.query(
|
|
50
|
+
'UPDATE Spare_Part SET TotalPrice = Quantity * UnitPrice WHERE SparePartID = ?',
|
|
51
|
+
[SparePartID]
|
|
52
|
+
);
|
|
53
|
+
await conn.commit();
|
|
54
|
+
res.status(201).json({ message: 'Stock out recorded successfully' });
|
|
55
|
+
} catch (err) {
|
|
56
|
+
await conn.rollback();
|
|
57
|
+
console.error(err);
|
|
58
|
+
res.status(500).json({ message: 'Server error' });
|
|
59
|
+
} finally {
|
|
60
|
+
conn.release();
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
router.put('/:id', requireAuth, async (req, res) => {
|
|
65
|
+
const { id } = req.params;
|
|
66
|
+
const { SparePartID, StockOutQuantity, StockOutUnitPrice, StockOutDate } = req.body;
|
|
67
|
+
if (!SparePartID || !StockOutQuantity || !StockOutUnitPrice || !StockOutDate) {
|
|
68
|
+
return res.status(400).json({ message: 'All fields are required' });
|
|
69
|
+
}
|
|
70
|
+
const StockOutTotalPrice = parseFloat(StockOutQuantity) * parseFloat(StockOutUnitPrice);
|
|
71
|
+
const conn = await db.getConnection();
|
|
72
|
+
try {
|
|
73
|
+
await conn.beginTransaction();
|
|
74
|
+
const [old] = await conn.query('SELECT * FROM Stock_Out WHERE StockOutID = ?', [id]);
|
|
75
|
+
if (old.length === 0) {
|
|
76
|
+
await conn.rollback();
|
|
77
|
+
return res.status(404).json({ message: 'Record not found' });
|
|
78
|
+
}
|
|
79
|
+
const oldRecord = old[0];
|
|
80
|
+
// Restore old quantity to the original spare part
|
|
81
|
+
await conn.query(
|
|
82
|
+
'UPDATE Spare_Part SET Quantity = Quantity + ? WHERE SparePartID = ?',
|
|
83
|
+
[oldRecord.StockOutQuantity, oldRecord.SparePartID]
|
|
84
|
+
);
|
|
85
|
+
// Check availability for new record
|
|
86
|
+
const [parts] = await conn.query('SELECT Quantity FROM Spare_Part WHERE SparePartID = ?', [SparePartID]);
|
|
87
|
+
if (parts.length === 0 || parts[0].Quantity < parseInt(StockOutQuantity)) {
|
|
88
|
+
await conn.rollback();
|
|
89
|
+
const available = parts.length > 0 ? parts[0].Quantity : 0;
|
|
90
|
+
return res.status(400).json({ message: `Insufficient stock. Available: ${available}` });
|
|
91
|
+
}
|
|
92
|
+
await conn.query(
|
|
93
|
+
'UPDATE Stock_Out SET SparePartID=?, StockOutQuantity=?, StockOutUnitPrice=?, StockOutTotalPrice=?, StockOutDate=? WHERE StockOutID=?',
|
|
94
|
+
[SparePartID, parseInt(StockOutQuantity), parseFloat(StockOutUnitPrice), StockOutTotalPrice, StockOutDate, id]
|
|
95
|
+
);
|
|
96
|
+
await conn.query(
|
|
97
|
+
'UPDATE Spare_Part SET Quantity = Quantity - ? WHERE SparePartID = ?',
|
|
98
|
+
[parseInt(StockOutQuantity), SparePartID]
|
|
99
|
+
);
|
|
100
|
+
await conn.query(
|
|
101
|
+
'UPDATE Spare_Part SET TotalPrice = Quantity * UnitPrice WHERE SparePartID = ?',
|
|
102
|
+
[SparePartID]
|
|
103
|
+
);
|
|
104
|
+
await conn.commit();
|
|
105
|
+
res.json({ message: 'Stock out updated successfully' });
|
|
106
|
+
} catch (err) {
|
|
107
|
+
await conn.rollback();
|
|
108
|
+
console.error(err);
|
|
109
|
+
res.status(500).json({ message: 'Server error' });
|
|
110
|
+
} finally {
|
|
111
|
+
conn.release();
|
|
112
|
+
}
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
router.delete('/:id', requireAuth, async (req, res) => {
|
|
116
|
+
const { id } = req.params;
|
|
117
|
+
const conn = await db.getConnection();
|
|
118
|
+
try {
|
|
119
|
+
await conn.beginTransaction();
|
|
120
|
+
const [old] = await conn.query('SELECT * FROM Stock_Out WHERE StockOutID = ?', [id]);
|
|
121
|
+
if (old.length === 0) {
|
|
122
|
+
await conn.rollback();
|
|
123
|
+
return res.status(404).json({ message: 'Record not found' });
|
|
124
|
+
}
|
|
125
|
+
const oldRecord = old[0];
|
|
126
|
+
await conn.query(
|
|
127
|
+
'UPDATE Spare_Part SET Quantity = Quantity + ? WHERE SparePartID = ?',
|
|
128
|
+
[oldRecord.StockOutQuantity, oldRecord.SparePartID]
|
|
129
|
+
);
|
|
130
|
+
await conn.query(
|
|
131
|
+
'UPDATE Spare_Part SET TotalPrice = Quantity * UnitPrice WHERE SparePartID = ?',
|
|
132
|
+
[oldRecord.SparePartID]
|
|
133
|
+
);
|
|
134
|
+
await conn.query('DELETE FROM Stock_Out WHERE StockOutID = ?', [id]);
|
|
135
|
+
await conn.commit();
|
|
136
|
+
res.json({ message: 'Stock out deleted successfully' });
|
|
137
|
+
} catch (err) {
|
|
138
|
+
await conn.rollback();
|
|
139
|
+
console.error(err);
|
|
140
|
+
res.status(500).json({ message: 'Server error' });
|
|
141
|
+
} finally {
|
|
142
|
+
conn.release();
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
module.exports = router;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require('dotenv').config();
|
|
2
|
+
const bcrypt = require('bcryptjs');
|
|
3
|
+
const db = require('./config/db');
|
|
4
|
+
|
|
5
|
+
async function seed() {
|
|
6
|
+
try {
|
|
7
|
+
const hashedPassword = await bcrypt.hash('admin123', 10);
|
|
8
|
+
await db.query(
|
|
9
|
+
'INSERT IGNORE INTO Users (Username, Password) VALUES (?, ?)',
|
|
10
|
+
['admin', hashedPassword]
|
|
11
|
+
);
|
|
12
|
+
console.log('Default admin user created: admin / admin123');
|
|
13
|
+
process.exit(0);
|
|
14
|
+
} catch (err) {
|
|
15
|
+
console.error('Seed failed:', err.message);
|
|
16
|
+
process.exit(1);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
seed();
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const cors = require('cors');
|
|
3
|
+
const session = require('express-session');
|
|
4
|
+
const bodyParser = require('body-parser');
|
|
5
|
+
require('dotenv').config();
|
|
6
|
+
|
|
7
|
+
const authRoutes = require('./routes/auth');
|
|
8
|
+
const sparePartRoutes = require('./routes/spareParts');
|
|
9
|
+
const stockInRoutes = require('./routes/stockIn');
|
|
10
|
+
const stockOutRoutes = require('./routes/stockOut');
|
|
11
|
+
const reportRoutes = require('./routes/reports');
|
|
12
|
+
|
|
13
|
+
const app = express();
|
|
14
|
+
|
|
15
|
+
app.use(cors({
|
|
16
|
+
origin: 'http://localhost:5173',
|
|
17
|
+
credentials: true
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
app.use(bodyParser.json());
|
|
21
|
+
app.use(bodyParser.urlencoded({ extended: true }));
|
|
22
|
+
|
|
23
|
+
app.use(session({
|
|
24
|
+
secret: process.env.SESSION_SECRET || 'sims-secret-key',
|
|
25
|
+
resave: false,
|
|
26
|
+
saveUninitialized: false,
|
|
27
|
+
cookie: {
|
|
28
|
+
secure: false,
|
|
29
|
+
httpOnly: true,
|
|
30
|
+
maxAge: 24 * 60 * 60 * 1000
|
|
31
|
+
}
|
|
32
|
+
}));
|
|
33
|
+
|
|
34
|
+
app.use('/api/auth', authRoutes);
|
|
35
|
+
app.use('/api/spare-parts', sparePartRoutes);
|
|
36
|
+
app.use('/api/stock-in', stockInRoutes);
|
|
37
|
+
app.use('/api/stock-out', stockOutRoutes);
|
|
38
|
+
app.use('/api/reports', reportRoutes);
|
|
39
|
+
|
|
40
|
+
const PORT = process.env.PORT || 5000;
|
|
41
|
+
app.listen(PORT, () => {
|
|
42
|
+
console.log(`SIMS Backend running on http://localhost:${PORT}`);
|
|
43
|
+
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
-- SIMS Database Setup
|
|
2
|
+
-- SmartPark Stock Inventory Management System
|
|
3
|
+
|
|
4
|
+
CREATE DATABASE IF NOT EXISTS SIMS;
|
|
5
|
+
USE SIMS;
|
|
6
|
+
|
|
7
|
+
CREATE TABLE IF NOT EXISTS Users (
|
|
8
|
+
UserID INT AUTO_INCREMENT PRIMARY KEY,
|
|
9
|
+
Username VARCHAR(50) NOT NULL UNIQUE,
|
|
10
|
+
Password VARCHAR(255) NOT NULL,
|
|
11
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
CREATE TABLE IF NOT EXISTS Spare_Part (
|
|
15
|
+
SparePartID INT AUTO_INCREMENT PRIMARY KEY,
|
|
16
|
+
Name VARCHAR(100) NOT NULL,
|
|
17
|
+
Category VARCHAR(50) NOT NULL,
|
|
18
|
+
Quantity INT NOT NULL DEFAULT 0,
|
|
19
|
+
UnitPrice DECIMAL(10, 2) NOT NULL,
|
|
20
|
+
TotalPrice DECIMAL(10, 2) GENERATED ALWAYS AS (Quantity * UnitPrice) STORED,
|
|
21
|
+
CreatedAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
CREATE TABLE IF NOT EXISTS Stock_In (
|
|
25
|
+
StockInID INT AUTO_INCREMENT PRIMARY KEY,
|
|
26
|
+
SparePartID INT NOT NULL,
|
|
27
|
+
StockInQuantity INT NOT NULL,
|
|
28
|
+
StockInDate DATE NOT NULL,
|
|
29
|
+
FOREIGN KEY (SparePartID) REFERENCES Spare_Part(SparePartID) ON DELETE CASCADE
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
CREATE TABLE IF NOT EXISTS Stock_Out (
|
|
33
|
+
StockOutID INT AUTO_INCREMENT PRIMARY KEY,
|
|
34
|
+
SparePartID INT NOT NULL,
|
|
35
|
+
StockOutQuantity INT NOT NULL,
|
|
36
|
+
StockOutUnitPrice DECIMAL(10, 2) NOT NULL,
|
|
37
|
+
StockOutTotalPrice DECIMAL(10, 2) NOT NULL,
|
|
38
|
+
StockOutDate DATE NOT NULL,
|
|
39
|
+
FOREIGN KEY (SparePartID) REFERENCES Spare_Part(SparePartID) ON DELETE CASCADE
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
-- Run `npm run seed` in backend-project to create default admin user
|
|
43
|
+
-- Default login: admin / admin123
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
6
|
+
<title>SIMS - SmartPark Stock Inventory</title>
|
|
7
|
+
</head>
|
|
8
|
+
<body>
|
|
9
|
+
<div id="root"></div>
|
|
10
|
+
<script type="module" src="/src/main.jsx"></script>
|
|
11
|
+
</body>
|
|
12
|
+
</html>
|