init
This commit is contained in:
@@ -0,0 +1,150 @@
|
||||
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;
|
||||
Reference in New Issue
Block a user