diff --git a/scripts/api-check.js b/scripts/api-check.js index a32941f..b51bb9d 100644 --- a/scripts/api-check.js +++ b/scripts/api-check.js @@ -355,6 +355,52 @@ async function run(port) { reassigned.status === 200 && reassigned.json.data.assignedDealerIds.includes(dealerC.json.data.id), 'assign dealer failed' ); + + const dealerD = await request(port, 'POST', '/api/admin/dealers', { + token: adminToken, + body: { name: 'Delete Motors', code: 'DEL', district: 'Colombo', phone: '94776666666' }, + }); + assert(dealerD.status === 201, 'dealer for delete test failed'); + await addStock('CH-DEL', 'EN-DEL', 1, dealerD.json.data.id); + const transferred = await request(port, 'POST', '/api/stocks/CH-DEL/transfer', { + token: adminToken, + body: { dealerId: dealerA.json.data.id }, + }); + assert(transferred.status === 200, 'transfer before delete failed'); + const dealerDToken = await approveDealer('94776666666', adminToken); + const doomedEvent = await request(port, 'POST', '/api/events', { + token: dealerDToken, + body: { + dealerId: dealerD.json.data.id, + planType: 'general', + title: 'Going away', + description: 'Removed with the dealer', + expense: 10, + imageUrls: [], + }, + }); + assert(doomedEvent.status === 201, 'event before delete failed'); + + const repDelete = await request(port, 'DELETE', `/api/admin/dealers/${dealerD.json.data.id}`, { + token: repToken, + }); + assert(repDelete.status === 403, 'sales rep should not delete a dealer'); + + const removed = await request(port, 'DELETE', `/api/admin/dealers/${dealerD.json.data.id}`, { + token: adminToken, + }); + assert(removed.status === 200, `dealer delete failed ${removed.status} ${JSON.stringify(removed.json)}`); + const dealerGone = await prisma.dealer.findUnique({ where: { id: dealerD.json.data.id } }); + const loginGone = await prisma.user.findUnique({ where: { phone: '94776666666' } }); + const eventGone = await prisma.event.findUnique({ where: { id: doomedEvent.json.data.id } }); + const stockKept = await prisma.stock.findUnique({ where: { chassisNumber: 'CH-DEL' } }); + assert(!dealerGone && !loginGone && !eventGone, 'dealer, login, and plans should be removed'); + assert(stockKept && stockKept.currentDealerId === dealerA.json.data.id, 'stock already transferred should stay'); + + const missingDelete = await request(port, 'DELETE', `/api/admin/dealers/${dealerD.json.data.id}`, { + token: adminToken, + }); + assert(missingDelete.status === 404, 'deleting a missing dealer should be 404'); } async function main() { diff --git a/src/routes/admin.js b/src/routes/admin.js index d2f400a..b908fa4 100644 --- a/src/routes/admin.js +++ b/src/routes/admin.js @@ -51,6 +51,63 @@ router.post( }) ); +router.delete( + '/dealers/:id', + requireRole('superAdmin'), + asyncHandler(async (req, res) => { + const id = String(req.params.id || '').trim(); + const dealer = await prisma.dealer.findUnique({ where: { id } }); + if (!dealer) throw httpError(404, 'Dealer not found'); + + await prisma.$transaction(async (tx) => { + const staff = await tx.user.findMany({ + where: { dealerId: id }, + select: { id: true }, + }); + const staffIds = staff.map((user) => user.id); + const stocks = await tx.stock.findMany({ + where: { currentDealerId: id }, + select: { id: true }, + }); + const stockIds = stocks.map((stock) => stock.id); + + await tx.stockTransfer.deleteMany({ + where: { + OR: [ + { fromDealerId: id }, + { toDealerId: id }, + ...(stockIds.length ? [{ stockId: { in: stockIds } }] : []), + ], + }, + }); + + if (staffIds.length) { + await tx.stockTransfer.updateMany({ + where: { actorId: { in: staffIds } }, + data: { actorId: req.user.id }, + }); + await tx.event.updateMany({ + where: { createdById: { in: staffIds }, dealerId: { not: id } }, + data: { createdById: req.user.id }, + }); + await tx.servicePoint.updateMany({ + where: { createdById: { in: staffIds } }, + data: { createdById: req.user.id }, + }); + } + + await tx.event.deleteMany({ where: { dealerId: id } }); + await tx.stock.deleteMany({ where: { currentDealerId: id } }); + if (staffIds.length) { + await tx.user.deleteMany({ where: { id: { in: staffIds } } }); + } + await tx.dealer.delete({ where: { id } }); + }); + + return res.json({ success: true }); + }) +); + router.get( '/sales-reps', requireRole('superAdmin'),