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,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "backend-project",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CRPMS Backend - Car Repair Payment Management System",
|
|
5
|
+
"main": "server.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"start": "node server.js",
|
|
8
|
+
"dev": "nodemon server.js",
|
|
9
|
+
"init-db": "node config/initDb.js"
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"bcryptjs": "^2.4.3",
|
|
13
|
+
"cors": "^2.8.5",
|
|
14
|
+
"express": "^4.18.2",
|
|
15
|
+
"express-session": "^1.17.3",
|
|
16
|
+
"mysql2": "^3.6.5"
|
|
17
|
+
},
|
|
18
|
+
"devDependencies": {
|
|
19
|
+
"nodemon": "^3.0.2"
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
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({ error: 'Username and password required.' });
|
|
8
|
+
}
|
|
9
|
+
req.session.user = { id: 1, username, fullName: username };
|
|
10
|
+
res.json({ message: 'Login successful', user: req.session.user });
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
router.post('/logout', (req, res) => {
|
|
14
|
+
req.session.destroy(() => {
|
|
15
|
+
res.json({ message: 'Logged out successfully.' });
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
router.get('/me', (req, res) => {
|
|
20
|
+
if (!req.session.user) {
|
|
21
|
+
return res.status(401).json({ error: 'Not authenticated.' });
|
|
22
|
+
}
|
|
23
|
+
res.json(req.session.user);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
module.exports = router;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const pool = require('../config/db');
|
|
3
|
+
const { requireAuth } = require('../middleware/auth');
|
|
4
|
+
const router = express.Router();
|
|
5
|
+
|
|
6
|
+
router.use(requireAuth);
|
|
7
|
+
|
|
8
|
+
router.post('/', async (req, res) => {
|
|
9
|
+
const { PlateNumber, type, Model, ManufacturingYear, DriverPhone, MechanicName } = req.body;
|
|
10
|
+
if (!PlateNumber || !type || !Model || !ManufacturingYear || !DriverPhone || !MechanicName) {
|
|
11
|
+
return res.status(400).json({ error: 'All fields are required.' });
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
await pool.query(
|
|
15
|
+
'INSERT INTO Car (PlateNumber, type, Model, ManufacturingYear, DriverPhone, MechanicName) VALUES (?,?,?,?,?,?)',
|
|
16
|
+
[PlateNumber, type, Model, ManufacturingYear, DriverPhone, MechanicName]
|
|
17
|
+
);
|
|
18
|
+
res.status(201).json({ message: 'Car recorded successfully.' });
|
|
19
|
+
} catch (err) {
|
|
20
|
+
if (err.code === 'ER_DUP_ENTRY') {
|
|
21
|
+
return res.status(409).json({ error: 'A car with this plate number already exists.' });
|
|
22
|
+
}
|
|
23
|
+
res.status(500).json({ error: 'Server error.' });
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
router.get('/', async (req, res) => {
|
|
28
|
+
try {
|
|
29
|
+
const [rows] = await pool.query('SELECT * FROM Car ORDER BY PlateNumber');
|
|
30
|
+
res.json(rows);
|
|
31
|
+
} catch (err) {
|
|
32
|
+
res.status(500).json({ error: 'Server error.' });
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
module.exports = router;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const pool = require('../config/db');
|
|
3
|
+
const { requireAuth } = require('../middleware/auth');
|
|
4
|
+
const router = express.Router();
|
|
5
|
+
|
|
6
|
+
router.use(requireAuth);
|
|
7
|
+
|
|
8
|
+
router.post('/', async (req, res) => {
|
|
9
|
+
const { AmountPaid, PaymentDate, RecordNumber } = req.body;
|
|
10
|
+
if (!AmountPaid || !PaymentDate || !RecordNumber) {
|
|
11
|
+
return res.status(400).json({ error: 'All fields are required.' });
|
|
12
|
+
}
|
|
13
|
+
const userId = req.session.user.id;
|
|
14
|
+
try {
|
|
15
|
+
const [result] = await pool.query(
|
|
16
|
+
'INSERT INTO Payment (AmountPaid, PaymentDate, RecordNumber, UserID) VALUES (?,?,?,?)',
|
|
17
|
+
[AmountPaid, PaymentDate, RecordNumber, userId]
|
|
18
|
+
);
|
|
19
|
+
res.status(201).json({ message: 'Payment recorded.', PaymentNumber: result.insertId });
|
|
20
|
+
} catch (err) {
|
|
21
|
+
res.status(500).json({ error: 'Server error.' });
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
router.get('/', async (req, res) => {
|
|
26
|
+
try {
|
|
27
|
+
const [rows] = await pool.query(`
|
|
28
|
+
SELECT p.PaymentNumber, p.AmountPaid, p.PaymentDate, p.RecordNumber,
|
|
29
|
+
u.FullName AS ReceivedBy,
|
|
30
|
+
sr.ServiceDate, sr.PlateNumber,
|
|
31
|
+
s.ServiceName, s.ServicePrice,
|
|
32
|
+
c.type, c.Model, c.DriverPhone
|
|
33
|
+
FROM Payment p
|
|
34
|
+
LEFT JOIN User u ON p.UserID = u.UserID
|
|
35
|
+
LEFT JOIN ServiceRecord sr ON p.RecordNumber = sr.RecordNumber
|
|
36
|
+
LEFT JOIN Services s ON sr.ServiceCode = s.ServiceCode
|
|
37
|
+
LEFT JOIN Car c ON sr.PlateNumber = c.PlateNumber
|
|
38
|
+
ORDER BY p.PaymentDate DESC
|
|
39
|
+
`);
|
|
40
|
+
res.json(rows);
|
|
41
|
+
} catch (err) {
|
|
42
|
+
res.status(500).json({ error: 'Server error.' });
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
// Get bill for a single payment
|
|
47
|
+
router.get('/:id/bill', async (req, res) => {
|
|
48
|
+
try {
|
|
49
|
+
const [rows] = await pool.query(`
|
|
50
|
+
SELECT p.PaymentNumber, p.AmountPaid, p.PaymentDate,
|
|
51
|
+
u.FullName AS ReceivedBy,
|
|
52
|
+
sr.RecordNumber, sr.ServiceDate, sr.PlateNumber,
|
|
53
|
+
s.ServiceName, s.ServicePrice,
|
|
54
|
+
c.type, c.Model, c.ManufacturingYear, c.DriverPhone, c.MechanicName
|
|
55
|
+
FROM Payment p
|
|
56
|
+
LEFT JOIN User u ON p.UserID = u.UserID
|
|
57
|
+
LEFT JOIN ServiceRecord sr ON p.RecordNumber = sr.RecordNumber
|
|
58
|
+
LEFT JOIN Services s ON sr.ServiceCode = s.ServiceCode
|
|
59
|
+
LEFT JOIN Car c ON sr.PlateNumber = c.PlateNumber
|
|
60
|
+
WHERE p.PaymentNumber = ?
|
|
61
|
+
`, [req.params.id]);
|
|
62
|
+
if (rows.length === 0) return res.status(404).json({ error: 'Payment not found.' });
|
|
63
|
+
res.json(rows[0]);
|
|
64
|
+
} catch (err) {
|
|
65
|
+
res.status(500).json({ error: 'Server error.' });
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
module.exports = router;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const pool = require('../config/db');
|
|
3
|
+
const { requireAuth } = require('../middleware/auth');
|
|
4
|
+
const router = express.Router();
|
|
5
|
+
|
|
6
|
+
router.use(requireAuth);
|
|
7
|
+
|
|
8
|
+
// Daily report: services offered and amount paid per car
|
|
9
|
+
router.get('/daily', async (req, res) => {
|
|
10
|
+
const { date } = req.query;
|
|
11
|
+
const reportDate = date || new Date().toISOString().split('T')[0];
|
|
12
|
+
try {
|
|
13
|
+
const [rows] = await pool.query(`
|
|
14
|
+
SELECT sr.RecordNumber, sr.ServiceDate, sr.PlateNumber,
|
|
15
|
+
c.type, c.Model, c.DriverPhone, c.MechanicName,
|
|
16
|
+
s.ServiceName, s.ServicePrice,
|
|
17
|
+
p.PaymentNumber, p.AmountPaid, p.PaymentDate,
|
|
18
|
+
u.FullName AS ReceivedBy
|
|
19
|
+
FROM ServiceRecord sr
|
|
20
|
+
LEFT JOIN Car c ON sr.PlateNumber = c.PlateNumber
|
|
21
|
+
LEFT JOIN Services s ON sr.ServiceCode = s.ServiceCode
|
|
22
|
+
LEFT JOIN Payment p ON sr.RecordNumber = p.RecordNumber
|
|
23
|
+
LEFT JOIN User u ON p.UserID = u.UserID
|
|
24
|
+
WHERE sr.ServiceDate = ?
|
|
25
|
+
ORDER BY sr.RecordNumber
|
|
26
|
+
`, [reportDate]);
|
|
27
|
+
|
|
28
|
+
const total = rows.reduce((sum, r) => sum + (parseFloat(r.AmountPaid) || 0), 0);
|
|
29
|
+
res.json({ date: reportDate, records: rows, totalCollected: total });
|
|
30
|
+
} catch (err) {
|
|
31
|
+
res.status(500).json({ error: 'Server error.' });
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
// Summary report: all payments with details
|
|
36
|
+
router.get('/summary', async (req, res) => {
|
|
37
|
+
try {
|
|
38
|
+
const [rows] = await pool.query(`
|
|
39
|
+
SELECT p.PaymentNumber, p.AmountPaid, p.PaymentDate,
|
|
40
|
+
u.FullName AS ReceivedBy,
|
|
41
|
+
sr.ServiceDate, sr.PlateNumber,
|
|
42
|
+
s.ServiceName, s.ServicePrice,
|
|
43
|
+
c.type, c.Model, c.DriverPhone
|
|
44
|
+
FROM Payment p
|
|
45
|
+
LEFT JOIN User u ON p.UserID = u.UserID
|
|
46
|
+
LEFT JOIN ServiceRecord sr ON p.RecordNumber = sr.RecordNumber
|
|
47
|
+
LEFT JOIN Services s ON sr.ServiceCode = s.ServiceCode
|
|
48
|
+
LEFT JOIN Car c ON sr.PlateNumber = c.PlateNumber
|
|
49
|
+
ORDER BY p.PaymentDate DESC
|
|
50
|
+
`);
|
|
51
|
+
const total = rows.reduce((sum, r) => sum + parseFloat(r.AmountPaid || 0), 0);
|
|
52
|
+
res.json({ records: rows, totalRevenue: total });
|
|
53
|
+
} catch (err) {
|
|
54
|
+
res.status(500).json({ error: 'Server error.' });
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
module.exports = router;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const pool = require('../config/db');
|
|
3
|
+
const { requireAuth } = require('../middleware/auth');
|
|
4
|
+
const router = express.Router();
|
|
5
|
+
|
|
6
|
+
router.use(requireAuth);
|
|
7
|
+
|
|
8
|
+
// INSERT
|
|
9
|
+
router.post('/', async (req, res) => {
|
|
10
|
+
const { ServiceDate, PlateNumber, ServiceCode } = req.body;
|
|
11
|
+
if (!ServiceDate || !PlateNumber || !ServiceCode) {
|
|
12
|
+
return res.status(400).json({ error: 'All fields are required.' });
|
|
13
|
+
}
|
|
14
|
+
try {
|
|
15
|
+
const [result] = await pool.query(
|
|
16
|
+
'INSERT INTO ServiceRecord (ServiceDate, PlateNumber, ServiceCode) VALUES (?,?,?)',
|
|
17
|
+
[ServiceDate, PlateNumber, ServiceCode]
|
|
18
|
+
);
|
|
19
|
+
res.status(201).json({ message: 'Service record created.', RecordNumber: result.insertId });
|
|
20
|
+
} catch (err) {
|
|
21
|
+
res.status(500).json({ error: 'Server error.' });
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
// RETRIEVE all
|
|
26
|
+
router.get('/', async (req, res) => {
|
|
27
|
+
try {
|
|
28
|
+
const [rows] = await pool.query(`
|
|
29
|
+
SELECT sr.RecordNumber, sr.ServiceDate, sr.PlateNumber, sr.ServiceCode,
|
|
30
|
+
c.type, c.Model, c.DriverPhone, c.MechanicName,
|
|
31
|
+
s.ServiceName, s.ServicePrice
|
|
32
|
+
FROM ServiceRecord sr
|
|
33
|
+
LEFT JOIN Car c ON sr.PlateNumber = c.PlateNumber
|
|
34
|
+
LEFT JOIN Services s ON sr.ServiceCode = s.ServiceCode
|
|
35
|
+
ORDER BY sr.RecordNumber DESC
|
|
36
|
+
`);
|
|
37
|
+
res.json(rows);
|
|
38
|
+
} catch (err) {
|
|
39
|
+
res.status(500).json({ error: 'Server error.' });
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// RETRIEVE one
|
|
44
|
+
router.get('/:id', async (req, res) => {
|
|
45
|
+
try {
|
|
46
|
+
const [rows] = await pool.query(`
|
|
47
|
+
SELECT sr.RecordNumber, sr.ServiceDate, sr.PlateNumber, sr.ServiceCode,
|
|
48
|
+
c.type, c.Model, c.DriverPhone, c.MechanicName,
|
|
49
|
+
s.ServiceName, s.ServicePrice
|
|
50
|
+
FROM ServiceRecord sr
|
|
51
|
+
LEFT JOIN Car c ON sr.PlateNumber = c.PlateNumber
|
|
52
|
+
LEFT JOIN Services s ON sr.ServiceCode = s.ServiceCode
|
|
53
|
+
WHERE sr.RecordNumber = ?
|
|
54
|
+
`, [req.params.id]);
|
|
55
|
+
if (rows.length === 0) return res.status(404).json({ error: 'Record not found.' });
|
|
56
|
+
res.json(rows[0]);
|
|
57
|
+
} catch (err) {
|
|
58
|
+
res.status(500).json({ error: 'Server error.' });
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// UPDATE
|
|
63
|
+
router.put('/:id', async (req, res) => {
|
|
64
|
+
const { ServiceDate, PlateNumber, ServiceCode } = req.body;
|
|
65
|
+
if (!ServiceDate || !PlateNumber || !ServiceCode) {
|
|
66
|
+
return res.status(400).json({ error: 'All fields are required.' });
|
|
67
|
+
}
|
|
68
|
+
try {
|
|
69
|
+
const [result] = await pool.query(
|
|
70
|
+
'UPDATE ServiceRecord SET ServiceDate=?, PlateNumber=?, ServiceCode=? WHERE RecordNumber=?',
|
|
71
|
+
[ServiceDate, PlateNumber, ServiceCode, req.params.id]
|
|
72
|
+
);
|
|
73
|
+
if (result.affectedRows === 0) return res.status(404).json({ error: 'Record not found.' });
|
|
74
|
+
res.json({ message: 'Service record updated.' });
|
|
75
|
+
} catch (err) {
|
|
76
|
+
res.status(500).json({ error: 'Server error.' });
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// DELETE
|
|
81
|
+
router.delete('/:id', async (req, res) => {
|
|
82
|
+
try {
|
|
83
|
+
const [result] = await pool.query('DELETE FROM ServiceRecord WHERE RecordNumber=?', [req.params.id]);
|
|
84
|
+
if (result.affectedRows === 0) return res.status(404).json({ error: 'Record not found.' });
|
|
85
|
+
res.json({ message: 'Service record deleted.' });
|
|
86
|
+
} catch (err) {
|
|
87
|
+
res.status(500).json({ error: 'Server error.' });
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
module.exports = router;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const pool = require('../config/db');
|
|
3
|
+
const { requireAuth } = require('../middleware/auth');
|
|
4
|
+
const router = express.Router();
|
|
5
|
+
|
|
6
|
+
router.use(requireAuth);
|
|
7
|
+
|
|
8
|
+
router.post('/', async (req, res) => {
|
|
9
|
+
const { ServiceCode, ServiceName, ServicePrice } = req.body;
|
|
10
|
+
if (!ServiceCode || !ServiceName || !ServicePrice) {
|
|
11
|
+
return res.status(400).json({ error: 'All fields are required.' });
|
|
12
|
+
}
|
|
13
|
+
try {
|
|
14
|
+
await pool.query(
|
|
15
|
+
'INSERT INTO Services (ServiceCode, ServiceName, ServicePrice) VALUES (?,?,?)',
|
|
16
|
+
[ServiceCode, ServiceName, ServicePrice]
|
|
17
|
+
);
|
|
18
|
+
res.status(201).json({ message: 'Service added successfully.' });
|
|
19
|
+
} catch (err) {
|
|
20
|
+
if (err.code === 'ER_DUP_ENTRY') {
|
|
21
|
+
return res.status(409).json({ error: 'A service with this code already exists.' });
|
|
22
|
+
}
|
|
23
|
+
res.status(500).json({ error: 'Server error.' });
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
router.get('/', async (req, res) => {
|
|
28
|
+
try {
|
|
29
|
+
const [rows] = await pool.query('SELECT * FROM Services ORDER BY ServiceCode');
|
|
30
|
+
res.json(rows);
|
|
31
|
+
} catch (err) {
|
|
32
|
+
res.status(500).json({ error: 'Server error.' });
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
module.exports = router;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
const express = require('express');
|
|
2
|
+
const cors = require('cors');
|
|
3
|
+
const session = require('express-session');
|
|
4
|
+
|
|
5
|
+
const authRoutes = require('./routes/auth');
|
|
6
|
+
const carRoutes = require('./routes/cars');
|
|
7
|
+
const serviceRoutes = require('./routes/services');
|
|
8
|
+
const serviceRecordRoutes = require('./routes/serviceRecords');
|
|
9
|
+
const paymentRoutes = require('./routes/payments');
|
|
10
|
+
const reportRoutes = require('./routes/reports');
|
|
11
|
+
|
|
12
|
+
const app = express();
|
|
13
|
+
const PORT = 5000;
|
|
14
|
+
|
|
15
|
+
app.use(cors({
|
|
16
|
+
origin: 'http://localhost:5173',
|
|
17
|
+
credentials: true,
|
|
18
|
+
}));
|
|
19
|
+
|
|
20
|
+
app.use(express.json());
|
|
21
|
+
|
|
22
|
+
app.use(session({
|
|
23
|
+
secret: 'crpms_secret_key_2025',
|
|
24
|
+
resave: false,
|
|
25
|
+
saveUninitialized: false,
|
|
26
|
+
cookie: {
|
|
27
|
+
secure: false,
|
|
28
|
+
httpOnly: true,
|
|
29
|
+
maxAge: 8 * 60 * 60 * 1000,
|
|
30
|
+
},
|
|
31
|
+
}));
|
|
32
|
+
|
|
33
|
+
app.use('/api/auth', authRoutes);
|
|
34
|
+
app.use('/api/cars', carRoutes);
|
|
35
|
+
app.use('/api/services', serviceRoutes);
|
|
36
|
+
app.use('/api/service-records', serviceRecordRoutes);
|
|
37
|
+
app.use('/api/payments', paymentRoutes);
|
|
38
|
+
app.use('/api/reports', reportRoutes);
|
|
39
|
+
|
|
40
|
+
app.get('/', (req, res) => res.json({ message: 'CRPMS API running.' }));
|
|
41
|
+
|
|
42
|
+
app.listen(PORT, () => {
|
|
43
|
+
console.log(`CRPMS backend running on http://localhost:${PORT}`);
|
|
44
|
+
});
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
-- CRPMS Database Setup
|
|
2
|
+
-- Car Repair Payment Management System
|
|
3
|
+
|
|
4
|
+
CREATE DATABASE IF NOT EXISTS CRPMS;
|
|
5
|
+
USE CRPMS;
|
|
6
|
+
|
|
7
|
+
CREATE TABLE IF NOT EXISTS Services (
|
|
8
|
+
ServiceCode VARCHAR(10) PRIMARY KEY,
|
|
9
|
+
ServiceName VARCHAR(100) NOT NULL,
|
|
10
|
+
ServicePrice DECIMAL(10,2) NOT NULL
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
CREATE TABLE IF NOT EXISTS Car (
|
|
14
|
+
PlateNumber VARCHAR(20) PRIMARY KEY,
|
|
15
|
+
type VARCHAR(50) NOT NULL,
|
|
16
|
+
Model VARCHAR(100) NOT NULL,
|
|
17
|
+
ManufacturingYear INT NOT NULL,
|
|
18
|
+
DriverPhone VARCHAR(15) NOT NULL,
|
|
19
|
+
MechanicName VARCHAR(100) NOT NULL
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
CREATE TABLE IF NOT EXISTS User (
|
|
23
|
+
UserID INT AUTO_INCREMENT PRIMARY KEY,
|
|
24
|
+
Username VARCHAR(50) UNIQUE NOT NULL,
|
|
25
|
+
Password VARCHAR(255) NOT NULL,
|
|
26
|
+
FullName VARCHAR(100) NOT NULL
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
CREATE TABLE IF NOT EXISTS ServiceRecord (
|
|
30
|
+
RecordNumber INT AUTO_INCREMENT PRIMARY KEY,
|
|
31
|
+
ServiceDate DATE NOT NULL,
|
|
32
|
+
PlateNumber VARCHAR(20),
|
|
33
|
+
ServiceCode VARCHAR(10),
|
|
34
|
+
FOREIGN KEY (PlateNumber) REFERENCES Car(PlateNumber) ON DELETE SET NULL,
|
|
35
|
+
FOREIGN KEY (ServiceCode) REFERENCES Services(ServiceCode) ON DELETE SET NULL
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
CREATE TABLE IF NOT EXISTS Payment (
|
|
39
|
+
PaymentNumber INT AUTO_INCREMENT PRIMARY KEY,
|
|
40
|
+
AmountPaid DECIMAL(10,2) NOT NULL,
|
|
41
|
+
PaymentDate DATE NOT NULL,
|
|
42
|
+
RecordNumber INT,
|
|
43
|
+
UserID INT,
|
|
44
|
+
FOREIGN KEY (RecordNumber) REFERENCES ServiceRecord(RecordNumber) ON DELETE SET NULL,
|
|
45
|
+
FOREIGN KEY (UserID) REFERENCES User(UserID) ON DELETE SET NULL
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
-- Seed services
|
|
49
|
+
INSERT IGNORE INTO Services (ServiceCode, ServiceName, ServicePrice) VALUES
|
|
50
|
+
('SRV001', 'Engine Repair', 150000),
|
|
51
|
+
('SRV002', 'Transmission Repair', 80000),
|
|
52
|
+
('SRV003', 'Oil Change', 60000),
|
|
53
|
+
('SRV004', 'Chain Replacement', 40000),
|
|
54
|
+
('SRV005', 'Disc Replacement', 400000),
|
|
55
|
+
('SRV006', 'Wheel Alignment', 5000);
|
|
56
|
+
|
|
57
|
+
-- Seed admin user (password: Admin@1234)
|
|
58
|
+
INSERT IGNORE INTO User (Username, Password, FullName) VALUES
|
|
59
|
+
('admin', '$2a$12$LJ3m4ys3Lk0TSwHCpNqzNeGwD8Y6m.sHfG.PEBjqMZdGLKxByNw8y', 'Chief Mechanic');
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# React + Vite
|
|
2
|
+
|
|
3
|
+
This template provides a minimal setup to get React working in Vite with HMR and some ESLint rules.
|
|
4
|
+
|
|
5
|
+
Currently, two official plugins are available:
|
|
6
|
+
|
|
7
|
+
- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs)
|
|
8
|
+
- [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/)
|
|
9
|
+
|
|
10
|
+
## React Compiler
|
|
11
|
+
|
|
12
|
+
The React Compiler is not enabled on this template because of its impact on dev & build performances. To add it, see [this documentation](https://react.dev/learn/react-compiler/installation).
|
|
13
|
+
|
|
14
|
+
## Expanding the ESLint configuration
|
|
15
|
+
|
|
16
|
+
If you are developing a production application, we recommend using TypeScript with type-aware lint rules enabled. Check out the [TS template](https://github.com/vitejs/vite/tree/main/packages/create-vite/template-react-ts) for information on how to integrate TypeScript and [`typescript-eslint`](https://typescript-eslint.io) in your project.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import js from '@eslint/js'
|
|
2
|
+
import globals from 'globals'
|
|
3
|
+
import reactHooks from 'eslint-plugin-react-hooks'
|
|
4
|
+
import reactRefresh from 'eslint-plugin-react-refresh'
|
|
5
|
+
import { defineConfig, globalIgnores } from 'eslint/config'
|
|
6
|
+
|
|
7
|
+
export default defineConfig([
|
|
8
|
+
globalIgnores(['dist']),
|
|
9
|
+
{
|
|
10
|
+
files: ['**/*.{js,jsx}'],
|
|
11
|
+
extends: [
|
|
12
|
+
js.configs.recommended,
|
|
13
|
+
reactHooks.configs.flat.recommended,
|
|
14
|
+
reactRefresh.configs.vite,
|
|
15
|
+
],
|
|
16
|
+
languageOptions: {
|
|
17
|
+
globals: globals.browser,
|
|
18
|
+
parserOptions: { ecmaFeatures: { jsx: true } },
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
])
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>frontend-project</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="root"></div>
|
|
11
|
+
<script type="module" src="/src/main.jsx"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|