add review and booking policies

This commit is contained in:
root
2026-05-25 18:29:05 -04:00
parent 8ed572b3bd
commit 0d969ab095
37 changed files with 3775 additions and 113 deletions
@@ -9,7 +9,7 @@ import { imageUpload, assertImageFiles } from '../../http/upload'
import * as service from './vehicle.service'
import {
vehicleSchema, listQuerySchema, availabilityQuerySchema, calendarQuerySchema,
calendarBlockSchema, maintenanceLogSchema, publishSchema,
calendarBlockSchema, maintenanceLogSchema, publishSchema, statusSchema,
idParamSchema, photoIdxSchema, blockIdParamSchema,
} from './vehicle.schemas'
@@ -76,6 +76,14 @@ router.delete('/:id/photos/:idx', requireRole('MANAGER'), async (req, res, next)
} catch (err) { next(err) }
})
router.patch('/:id/status', requireRole('MANAGER'), async (req, res, next) => {
try {
const { id } = parseParams(idParamSchema, req)
const { status } = parseBody(statusSchema, req)
ok(res, await service.setStatus(id, req.companyId, status))
} catch (err) { next(err) }
})
router.patch('/:id/publish', requireRole('MANAGER'), async (req, res, next) => {
try {
const { id } = parseParams(idParamSchema, req)
@@ -16,7 +16,7 @@ export const vehicleSchema = z.object({
mileage: z.number().int().optional(),
notes: z.string().optional(),
isPublished: z.boolean().default(true),
status: z.enum(['AVAILABLE', 'RENTED', 'MAINTENANCE', 'OUT_OF_SERVICE']).optional(),
status: z.enum(['AVAILABLE', 'RESERVED', 'READY', 'RENTED', 'RETURNED', 'NEEDS_CLEANING', 'MAINTENANCE', 'DAMAGE_REVIEW', 'OUT_OF_SERVICE']).optional(),
pickupLocations: z.array(z.string().trim().min(1)).default([]),
allowDifferentDropoff: z.boolean().default(false),
dropoffLocations: z.array(z.string().trim().min(1)).default([]),
@@ -58,6 +58,7 @@ export const maintenanceLogSchema = z.object({
})
export const publishSchema = z.object({ isPublished: z.boolean() })
export const statusSchema = z.object({ status: z.enum(['AVAILABLE', 'RESERVED', 'READY', 'RENTED', 'RETURNED', 'NEEDS_CLEANING', 'MAINTENANCE', 'DAMAGE_REVIEW', 'OUT_OF_SERVICE']) })
export const idParamSchema = z.object({ id: z.string() })
export const photoIdxSchema = z.object({ id: z.string(), idx: z.string() })
@@ -61,18 +61,25 @@ export async function createVehicle(data: any, companyId: string) {
return presentVehicle(await repo.create({ ...applyLocationSettings(data), companyId }))
}
const PUBLISHED_STATUSES = new Set(['AVAILABLE', 'RESERVED', 'READY', 'RENTED'])
export async function updateVehicle(id: string, companyId: string, data: any) {
const patch = applyLocationSettings(data)
if (patch.status === 'MAINTENANCE' || patch.status === 'OUT_OF_SERVICE') {
patch.isPublished = false
} else if (patch.status === 'AVAILABLE' || patch.status === 'RENTED') {
patch.isPublished = true
if (patch.status) {
patch.isPublished = PUBLISHED_STATUSES.has(patch.status)
}
const existing = await repo.findFirst(id, companyId)
if (!existing) throw new NotFoundError('Vehicle not found')
return presentVehicle(await repo.updateById(id, patch))
}
export async function setStatus(id: string, companyId: string, status: string) {
const existing = await repo.findFirst(id, companyId)
if (!existing) throw new NotFoundError('Vehicle not found')
const isPublished = PUBLISHED_STATUSES.has(status)
return presentVehicle(await repo.updateById(id, { status, isPublished }))
}
export async function deleteVehicle(id: string, companyId: string) {
return repo.softDelete(id, companyId)
}