Files
senaro_dealer_api/src/routes/admin.js
T
2026-10-01 11:52:17 +05:30

151 lines
5.0 KiB
JavaScript

const express = require('express');
const prisma = require('../db');
const { asyncHandler, httpError } = require('../lib/errors');
const { isValidPhone, normalizePhone } = require('../lib/phone');
const { canAccessDealer } = require('../lib/access');
const { userPublicSelect, publicUser } = require('../lib/users');
const { requireAuth, requireRole } = require('../middleware/auth');
const router = express.Router();
router.use(requireAuth);
router.get(
'/dealers',
requireRole('superAdmin'),
asyncHandler(async (req, res) => {
const dealers = await prisma.dealer.findMany({ orderBy: { name: 'asc' } });
return res.json({ success: true, data: dealers });
})
);
router.post(
'/dealers',
requireRole('superAdmin'),
asyncHandler(async (req, res) => {
const name = String(req.body?.name || '').trim();
const code = String(req.body?.code || '').trim();
const district = String(req.body?.district || '').trim() || null;
const address = String(req.body?.address || '').trim() || null;
const rawPhone = String(req.body?.phone || '').trim();
const phone = rawPhone ? normalizePhone(rawPhone) : null;
if (!name || !code) throw httpError(400, 'Name and code are required');
if (phone && !isValidPhone(phone)) {
throw httpError(400, 'Dealer phone must be a Sri Lankan mobile number');
}
const dealer = await prisma.dealer.create({
data: { name, code, district, address, phone },
});
return res.status(201).json({ success: true, data: dealer });
})
);
router.get(
'/sales-reps',
requireRole('superAdmin'),
asyncHandler(async (req, res) => {
const reps = await prisma.user.findMany({
where: { role: 'salesRep' },
select: userPublicSelect,
orderBy: { name: 'asc' },
});
return res.json({ success: true, data: reps.map((rep) => publicUser(rep)) });
})
);
router.post(
'/sales-reps',
requireRole('superAdmin'),
asyncHandler(async (req, res) => {
const name = String(req.body?.name || '').trim();
const phone = normalizePhone(req.body?.phone);
const dealerIds = Array.isArray(req.body?.dealerIds) ? req.body.dealerIds : [];
if (!name || !isValidPhone(phone)) {
throw httpError(400, 'Name and a 947XXXXXXXX phone are required');
}
if (!dealerIds.every((id) => typeof id === 'string' && id.trim())) {
throw httpError(400, 'dealerIds must be a list of ids');
}
const uniqueIds = [...new Set(dealerIds.map((id) => id.trim()))];
if (uniqueIds.length) {
const found = await prisma.dealer.findMany({ where: { id: { in: uniqueIds } } });
if (found.length !== uniqueIds.length) throw httpError(404, 'Dealer not found');
}
const user = await prisma.user.create({
data: {
name,
phone,
role: 'salesRep',
assignments: {
create: uniqueIds.map((dealerId) => ({ dealerId })),
},
},
select: userPublicSelect,
});
return res.status(201).json({ success: true, data: publicUser(user) });
})
);
router.patch(
'/assign-dealer',
requireRole('superAdmin'),
asyncHandler(async (req, res) => {
const salesRepId = String(req.body?.salesRepId || '').trim();
const dealerId = String(req.body?.dealerId || '').trim();
const assigned = req.body?.assigned !== false;
if (!salesRepId || !dealerId) {
throw httpError(400, 'salesRepId and dealerId are required');
}
const [rep, dealer] = await Promise.all([
prisma.user.findUnique({ where: { id: salesRepId } }),
prisma.dealer.findUnique({ where: { id: dealerId } }),
]);
if (!rep || rep.role !== 'salesRep') throw httpError(404, 'Sales rep not found');
if (!dealer) throw httpError(404, 'Dealer not found');
if (assigned) {
await prisma.dealerAssignment.upsert({
where: { salesRepId_dealerId: { salesRepId, dealerId } },
update: {},
create: { salesRepId, dealerId },
});
} else {
await prisma.dealerAssignment.deleteMany({ where: { salesRepId, dealerId } });
}
const updated = await prisma.user.findUnique({
where: { id: salesRepId },
select: userPublicSelect,
});
return res.json({ success: true, data: publicUser(updated) });
})
);
router.post(
'/dealer-users',
requireRole('superAdmin', 'salesRep'),
asyncHandler(async (req, res) => {
const name = String(req.body?.name || '').trim();
const phone = normalizePhone(req.body?.phone);
const dealerId = String(req.body?.dealerId || '').trim();
if (!name || !isValidPhone(phone) || !dealerId) {
throw httpError(400, 'Name, phone, and dealerId are required');
}
if (!canAccessDealer(req.user, dealerId)) throw httpError(403, 'Forbidden');
const dealer = await prisma.dealer.findUnique({ where: { id: dealerId } });
if (!dealer) throw httpError(404, 'Dealer not found');
const user = await prisma.user.create({
data: { name, phone, role: 'dealer', dealerId },
select: userPublicSelect,
});
return res.status(201).json({ success: true, data: publicUser(user) });
})
);
module.exports = router;