diff --git a/apps/api/src/routes/customers.ts b/apps/api/src/routes/customers.ts index 0807286..8c7fa9d 100644 --- a/apps/api/src/routes/customers.ts +++ b/apps/api/src/routes/customers.ts @@ -80,11 +80,12 @@ router.get('/:id', async (req, res, next) => { router.patch('/:id', requireRole('MANAGER'), async (req, res, next) => { try { + const { id } = z.object({ id: z.string() }).parse(req.params) const body = customerSchema.partial().parse(req.body) - const updated = await prisma.customer.updateMany({ where: { id: req.params.id, companyId: req.companyId }, data: { ...body, dateOfBirth: body.dateOfBirth ? new Date(body.dateOfBirth) : undefined, licenseExpiry: body.licenseExpiry ? new Date(body.licenseExpiry) : undefined, licenseIssuedAt: body.licenseIssuedAt ? new Date(body.licenseIssuedAt) : undefined } as any }) + const updated = await prisma.customer.updateMany({ where: { id, companyId: req.companyId }, data: { ...body, dateOfBirth: body.dateOfBirth ? new Date(body.dateOfBirth) : undefined, licenseExpiry: body.licenseExpiry ? new Date(body.licenseExpiry) : undefined, licenseIssuedAt: body.licenseIssuedAt ? new Date(body.licenseIssuedAt) : undefined } as any }) if (updated.count === 0) return res.status(404).json({ error: 'not_found', message: 'Customer not found', statusCode: 404 }) - if (body.licenseExpiry) await validateAndFlagLicense(req.params.id).catch(() => null) - const customer = await prisma.customer.findUniqueOrThrow({ where: { id: req.params.id } }) + if (body.licenseExpiry) await validateAndFlagLicense(id).catch(() => null) + const customer = await prisma.customer.findUniqueOrThrow({ where: { id } }) res.json({ data: customer }) } catch (err) { next(err) } }) diff --git a/apps/api/src/routes/offers.ts b/apps/api/src/routes/offers.ts index e06b41d..7cd11d1 100644 --- a/apps/api/src/routes/offers.ts +++ b/apps/api/src/routes/offers.ts @@ -61,19 +61,20 @@ router.get('/:id', async (req, res, next) => { router.patch('/:id', requireRole('MANAGER'), async (req, res, next) => { try { + const { id } = z.object({ id: z.string() }).parse(req.params) const { vehicleIds, ...body } = offerSchema.partial().parse(req.body) - const existing = await prisma.offer.findFirst({ where: { id: req.params.id, companyId: req.companyId } }) + const existing = await prisma.offer.findFirst({ where: { id, companyId: req.companyId } }) if (!existing) return res.status(404).json({ error: 'not_found', message: 'Offer not found', statusCode: 404 }) await prisma.$transaction(async (tx) => { - await tx.offer.update({ where: { id: req.params.id }, data: { ...body, validFrom: body.validFrom ? new Date(body.validFrom) : undefined, validUntil: body.validUntil ? new Date(body.validUntil) : undefined } }) + await tx.offer.update({ where: { id }, data: { ...body, validFrom: body.validFrom ? new Date(body.validFrom) : undefined, validUntil: body.validUntil ? new Date(body.validUntil) : undefined } }) if (vehicleIds !== undefined) { - await tx.offerVehicle.deleteMany({ where: { offerId: req.params.id } }) + await tx.offerVehicle.deleteMany({ where: { offerId: id } }) if (vehicleIds.length > 0) { - await tx.offerVehicle.createMany({ data: vehicleIds.map((vehicleId) => ({ offerId: req.params.id, vehicleId })) }) + await tx.offerVehicle.createMany({ data: vehicleIds.map((vehicleId) => ({ offerId: id, vehicleId })) }) } } }) - const updated = await prisma.offer.findUniqueOrThrow({ where: { id: req.params.id }, include: { vehicles: true } }) + const updated = await prisma.offer.findUniqueOrThrow({ where: { id }, include: { vehicles: true } }) res.json({ data: updated }) } catch (err) { next(err) } }) diff --git a/apps/api/src/routes/vehicles.ts b/apps/api/src/routes/vehicles.ts index cedeee3..06825b7 100644 --- a/apps/api/src/routes/vehicles.ts +++ b/apps/api/src/routes/vehicles.ts @@ -98,8 +98,9 @@ router.post('/:id/photos', requireRole('MANAGER'), upload.array('photos', 10), a router.delete('/:id/photos/:idx', requireRole('MANAGER'), async (req, res, next) => { try { - const vehicle = await prisma.vehicle.findFirstOrThrow({ where: { id: req.params.id, companyId: req.companyId } }) - const idx = parseInt(req.params.idx) + const { id, idx: idxParam } = z.object({ id: z.string(), idx: z.string() }).parse(req.params) + const vehicle = await prisma.vehicle.findFirstOrThrow({ where: { id, companyId: req.companyId } }) + const idx = parseInt(idxParam, 10) const photos = vehicle.photos.filter((_: string, i: number) => i !== idx) const updated = await prisma.vehicle.update({ where: { id: vehicle.id }, data: { photos } }) res.json({ data: updated }) @@ -217,6 +218,7 @@ router.get('/:id/calendar', async (req, res, next) => { router.post('/:id/calendar/blocks', requireRole('MANAGER'), async (req, res, next) => { try { + const { id } = z.object({ id: z.string() }).parse(req.params) const body = z.object({ startDate: z.string().datetime({ offset: true }).or(z.string().regex(/^\d{4}-\d{2}-\d{2}$/)), endDate: z.string().datetime({ offset: true }).or(z.string().regex(/^\d{4}-\d{2}-\d{2}$/)), @@ -228,11 +230,11 @@ router.post('/:id/calendar/blocks', requireRole('MANAGER'), async (req, res, nex const end = new Date(body.endDate) if (end <= start) return res.status(400).json({ error: 'invalid_range', message: 'endDate must be after startDate', statusCode: 400 }) - await prisma.vehicle.findFirstOrThrow({ where: { id: req.params.id, companyId: req.companyId } }) + await prisma.vehicle.findFirstOrThrow({ where: { id, companyId: req.companyId } }) const block = await prisma.vehicleCalendarBlock.create({ data: { - vehicleId: req.params.id, + vehicleId: id, startDate: start, endDate: end, reason: body.reason, @@ -262,6 +264,7 @@ router.get('/:id/maintenance', async (req, res, next) => { router.post('/:id/maintenance', requireRole('MANAGER'), async (req, res, next) => { try { + const { id } = z.object({ id: z.string() }).parse(req.params) const body = z.object({ type: z.string().min(1), description: z.string().optional(), @@ -273,8 +276,8 @@ router.post('/:id/maintenance', requireRole('MANAGER'), async (req, res, next) = }).parse(req.body) // Validate vehicle belongs to company - await prisma.vehicle.findFirstOrThrow({ where: { id: req.params.id, companyId: req.companyId } }) - const log = await prisma.maintenanceLog.create({ data: { ...body, vehicleId: req.params.id, performedAt: new Date(body.performedAt), nextDueAt: body.nextDueAt ? new Date(body.nextDueAt) : undefined } }) + await prisma.vehicle.findFirstOrThrow({ where: { id, companyId: req.companyId } }) + const log = await prisma.maintenanceLog.create({ data: { ...body, vehicleId: id, performedAt: new Date(body.performedAt), nextDueAt: body.nextDueAt ? new Date(body.nextDueAt) : undefined } }) res.status(201).json({ data: log }) } catch (err) { next(err) } })