dashboard fix
This commit is contained in:
BIN
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
@@ -3,10 +3,11 @@ import { prisma } from '../lib/prisma'
|
||||
import { requireCompanyAuth } from '../middleware/requireCompanyAuth'
|
||||
import { requireTenant } from '../middleware/requireTenant'
|
||||
import { requireSubscription } from '../middleware/requireSubscription'
|
||||
import { requireRole } from '../middleware/requireRole'
|
||||
import { generateFinancialReport, toCsv } from '../services/financialReportService'
|
||||
|
||||
const router = Router()
|
||||
router.use(requireCompanyAuth, requireTenant, requireSubscription)
|
||||
router.use(requireCompanyAuth, requireTenant, requireSubscription, requireRole('MANAGER'))
|
||||
|
||||
function getRangeFromPeriod(period: string) {
|
||||
const now = new Date()
|
||||
|
||||
@@ -21,6 +21,7 @@ const signupSchema = z.object({
|
||||
companyPhone: z.string().min(1).max(80),
|
||||
fax: z.string().max(80).optional(),
|
||||
yearsActive: z.string().min(1).max(80),
|
||||
preferredLanguage: z.enum(['en', 'fr', 'ar']).default('en'),
|
||||
plan: z.enum(['STARTER', 'GROWTH', 'PRO']),
|
||||
billingPeriod: z.enum(['MONTHLY', 'ANNUAL']),
|
||||
currency: z.enum(['MAD', 'USD', 'EUR']),
|
||||
@@ -196,6 +197,7 @@ router.post('/signup', async (req, res, next) => {
|
||||
phone: body.companyPhone,
|
||||
passwordHash,
|
||||
role: 'OWNER',
|
||||
preferredLanguage: body.preferredLanguage,
|
||||
isActive: true,
|
||||
},
|
||||
})
|
||||
|
||||
@@ -97,6 +97,7 @@ router.get('/me', async (req, res, next) => {
|
||||
firstName: employee.firstName,
|
||||
lastName: employee.lastName,
|
||||
role: employee.role,
|
||||
preferredLanguage: employee.preferredLanguage,
|
||||
companyId: employee.companyId,
|
||||
companyName: employee.company.name,
|
||||
companySlug: employee.company.slug,
|
||||
@@ -142,6 +143,7 @@ router.post('/login', async (req, res, next) => {
|
||||
firstName: employee.firstName,
|
||||
lastName: employee.lastName,
|
||||
role: employee.role,
|
||||
preferredLanguage: employee.preferredLanguage,
|
||||
companyId: employee.companyId,
|
||||
companyName: employee.company.name,
|
||||
companySlug: employee.company.slug,
|
||||
|
||||
@@ -6,6 +6,7 @@ import { uploadImage } from '../lib/storage'
|
||||
import { requireCompanyAuth } from '../middleware/requireCompanyAuth'
|
||||
import { requireTenant } from '../middleware/requireTenant'
|
||||
import { requireSubscription } from '../middleware/requireSubscription'
|
||||
import { requireRole } from '../middleware/requireRole'
|
||||
|
||||
const router = Router()
|
||||
const upload = multer({ storage: multer.memoryStorage(), limits: { fileSize: 10 * 1024 * 1024 } })
|
||||
@@ -212,7 +213,7 @@ router.get('/me', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.patch('/me', async (req, res, next) => {
|
||||
router.patch('/me', requireRole('OWNER'), async (req, res, next) => {
|
||||
try {
|
||||
const body = companySchema.parse(req.body)
|
||||
const company = await prisma.company.update({
|
||||
@@ -232,7 +233,7 @@ router.get('/me/brand', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.patch('/me/brand', async (req, res, next) => {
|
||||
router.patch('/me/brand', requireRole('OWNER'), async (req, res, next) => {
|
||||
try {
|
||||
const body = brandSchema.parse(req.body)
|
||||
const current = await prisma.brandSettings.findUnique({ where: { companyId: req.companyId } })
|
||||
@@ -256,7 +257,7 @@ router.patch('/me/brand', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.post('/me/brand/logo', upload.single('file'), async (req, res, next) => {
|
||||
router.post('/me/brand/logo', requireRole('OWNER'), upload.single('file'), async (req, res, next) => {
|
||||
try {
|
||||
if (!req.file) {
|
||||
return res.status(400).json({ error: 'missing_file', message: 'A logo file is required', statusCode: 400 })
|
||||
@@ -276,7 +277,7 @@ router.post('/me/brand/logo', upload.single('file'), async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.post('/me/brand/hero', upload.single('file'), async (req, res, next) => {
|
||||
router.post('/me/brand/hero', requireRole('OWNER'), upload.single('file'), async (req, res, next) => {
|
||||
try {
|
||||
if (!req.file) {
|
||||
return res.status(400).json({ error: 'missing_file', message: 'A hero image file is required', statusCode: 400 })
|
||||
@@ -296,7 +297,7 @@ router.post('/me/brand/hero', upload.single('file'), async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.post('/me/brand/subdomain/check', async (req, res, next) => {
|
||||
router.post('/me/brand/subdomain/check', requireRole('OWNER'), async (req, res, next) => {
|
||||
try {
|
||||
const { subdomain } = z.object({ subdomain: z.string().min(3) }).parse(req.body)
|
||||
const existing = await prisma.brandSettings.findFirst({
|
||||
@@ -306,7 +307,7 @@ router.post('/me/brand/subdomain/check', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.post('/me/brand/custom-domain', async (req, res, next) => {
|
||||
router.post('/me/brand/custom-domain', requireRole('OWNER'), async (req, res, next) => {
|
||||
try {
|
||||
const { customDomain } = z.object({ customDomain: z.string().min(3) }).parse(req.body)
|
||||
const normalized = customDomain.toLowerCase().trim()
|
||||
@@ -351,7 +352,7 @@ router.get('/me/brand/custom-domain/status', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.delete('/me/brand/custom-domain', async (req, res, next) => {
|
||||
router.delete('/me/brand/custom-domain', requireRole('OWNER'), async (req, res, next) => {
|
||||
try {
|
||||
const brand = await prisma.brandSettings.updateMany({
|
||||
where: { companyId: req.companyId },
|
||||
@@ -368,7 +369,7 @@ router.get('/me/contract-settings', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.patch('/me/contract-settings', async (req, res, next) => {
|
||||
router.patch('/me/contract-settings', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const body = contractSettingsSchema.parse(req.body)
|
||||
const settings = await prisma.contractSettings.upsert({
|
||||
@@ -390,7 +391,7 @@ router.get('/me/insurance-policies', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.post('/me/insurance-policies', async (req, res, next) => {
|
||||
router.post('/me/insurance-policies', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const body = insurancePolicySchema.parse(req.body)
|
||||
const policy = await prisma.insurancePolicy.create({ data: { companyId: req.companyId, ...body } })
|
||||
@@ -398,7 +399,7 @@ router.post('/me/insurance-policies', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.patch('/me/insurance-policies/:id', async (req, res, next) => {
|
||||
router.patch('/me/insurance-policies/:id', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const body = insurancePolicySchema.partial().parse(req.body)
|
||||
const policy = await prisma.insurancePolicy.updateMany({
|
||||
@@ -411,7 +412,7 @@ router.patch('/me/insurance-policies/:id', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.delete('/me/insurance-policies/:id', async (req, res, next) => {
|
||||
router.delete('/me/insurance-policies/:id', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const deleted = await prisma.insurancePolicy.deleteMany({ where: { id: req.params.id, companyId: req.companyId } })
|
||||
if (deleted.count === 0) return res.status(404).json({ error: 'not_found', message: 'Insurance policy not found', statusCode: 404 })
|
||||
@@ -429,7 +430,7 @@ router.get('/me/pricing-rules', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.post('/me/pricing-rules', async (req, res, next) => {
|
||||
router.post('/me/pricing-rules', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const body = pricingRuleSchema.parse(req.body)
|
||||
const rule = await prisma.pricingRule.create({ data: { companyId: req.companyId, ...body } })
|
||||
@@ -437,7 +438,7 @@ router.post('/me/pricing-rules', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.patch('/me/pricing-rules/:id', async (req, res, next) => {
|
||||
router.patch('/me/pricing-rules/:id', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const body = pricingRuleSchema.partial().parse(req.body)
|
||||
const updated = await prisma.pricingRule.updateMany({
|
||||
|
||||
@@ -78,7 +78,7 @@ router.get('/:id', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.patch('/:id', async (req, res, next) => {
|
||||
router.patch('/:id', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
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 })
|
||||
@@ -89,7 +89,7 @@ router.patch('/:id', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.post('/:id/flag', async (req, res, next) => {
|
||||
router.post('/:id/flag', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const { reason } = z.object({ reason: z.string().optional() }).parse(req.body)
|
||||
await prisma.customer.updateMany({ where: { id: req.params.id, companyId: req.companyId }, data: { flagged: true, flagReason: reason ?? null } })
|
||||
@@ -97,7 +97,7 @@ router.post('/:id/flag', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.delete('/:id/flag', async (req, res, next) => {
|
||||
router.delete('/:id/flag', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
await prisma.customer.updateMany({ where: { id: req.params.id, companyId: req.companyId }, data: { flagged: false, flagReason: null } })
|
||||
res.json({ data: { success: true } })
|
||||
|
||||
@@ -4,6 +4,7 @@ import { prisma } from '../lib/prisma'
|
||||
import { requireCompanyAuth } from '../middleware/requireCompanyAuth'
|
||||
import { requireTenant } from '../middleware/requireTenant'
|
||||
import { requireSubscription } from '../middleware/requireSubscription'
|
||||
import { requireRole } from '../middleware/requireRole'
|
||||
|
||||
const router = Router()
|
||||
router.use(requireCompanyAuth, requireTenant, requireSubscription)
|
||||
@@ -40,7 +41,7 @@ router.get('/', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.post('/', async (req, res, next) => {
|
||||
router.post('/', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const { vehicleIds, ...body } = offerSchema.parse(req.body)
|
||||
const offer = await prisma.offer.create({
|
||||
@@ -58,7 +59,7 @@ router.get('/:id', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.patch('/:id', async (req, res, next) => {
|
||||
router.patch('/:id', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const { vehicleIds, ...body } = offerSchema.partial().parse(req.body)
|
||||
const existing = await prisma.offer.findFirst({ where: { id: req.params.id, companyId: req.companyId } })
|
||||
@@ -77,21 +78,21 @@ router.patch('/:id', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.delete('/:id', async (req, res, next) => {
|
||||
router.delete('/:id', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
await prisma.offer.deleteMany({ where: { id: req.params.id, companyId: req.companyId } })
|
||||
res.json({ data: { success: true } })
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.post('/:id/activate', async (req, res, next) => {
|
||||
router.post('/:id/activate', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
await prisma.offer.updateMany({ where: { id: req.params.id, companyId: req.companyId }, data: { isActive: true } })
|
||||
res.json({ data: { success: true } })
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.post('/:id/deactivate', async (req, res, next) => {
|
||||
router.post('/:id/deactivate', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
await prisma.offer.updateMany({ where: { id: req.params.id, companyId: req.companyId }, data: { isActive: false } })
|
||||
res.json({ data: { success: true } })
|
||||
|
||||
@@ -4,6 +4,7 @@ import { prisma } from '../lib/prisma'
|
||||
import { requireCompanyAuth } from '../middleware/requireCompanyAuth'
|
||||
import { requireTenant } from '../middleware/requireTenant'
|
||||
import { requireSubscription } from '../middleware/requireSubscription'
|
||||
import { requireRole } from '../middleware/requireRole'
|
||||
import * as amanpay from '../services/amanpayService'
|
||||
import * as paypal from '../services/paypalService'
|
||||
|
||||
@@ -135,7 +136,7 @@ router.get('/reservations/:id', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.post('/reservations/:id/charge', async (req, res, next) => {
|
||||
router.post('/reservations/:id/charge', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const { provider, type, currency, successUrl, failureUrl } = chargeSchema.parse(req.body)
|
||||
|
||||
@@ -208,7 +209,7 @@ router.post('/reservations/:id/charge', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.post('/reservations/:id/capture-paypal', async (req, res, next) => {
|
||||
router.post('/reservations/:id/capture-paypal', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const { paypalOrderId } = z.object({ paypalOrderId: z.string() }).parse(req.body)
|
||||
|
||||
@@ -233,7 +234,7 @@ router.post('/reservations/:id/capture-paypal', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.post('/reservations/:id/manual', async (req, res, next) => {
|
||||
router.post('/reservations/:id/manual', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const { amount, currency, type, paymentMethod } = manualPaymentSchema.parse(req.body)
|
||||
|
||||
@@ -278,7 +279,7 @@ router.post('/reservations/:id/manual', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.post('/reservations/:reservationId/payments/:paymentId/refund', async (req, res, next) => {
|
||||
router.post('/reservations/:reservationId/payments/:paymentId/refund', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const { amount, reason } = z.object({
|
||||
amount: z.number().int().positive().optional(),
|
||||
|
||||
@@ -4,6 +4,7 @@ import { PLAN_PRICES } from '@rentaldrivego/types'
|
||||
import { prisma } from '../lib/prisma'
|
||||
import { requireCompanyAuth } from '../middleware/requireCompanyAuth'
|
||||
import { requireTenant } from '../middleware/requireTenant'
|
||||
import { requireRole } from '../middleware/requireRole'
|
||||
import * as amanpay from '../services/amanpayService'
|
||||
import * as paypal from '../services/paypalService'
|
||||
|
||||
@@ -164,7 +165,7 @@ const checkoutSchema = z.object({
|
||||
failureUrl: z.string().url(),
|
||||
})
|
||||
|
||||
router.post('/checkout', async (req, res, next) => {
|
||||
router.post('/checkout', requireRole('OWNER'), async (req, res, next) => {
|
||||
try {
|
||||
const body = checkoutSchema.parse(req.body)
|
||||
const prices = PLAN_PRICES[body.plan]?.[body.billingPeriod]
|
||||
@@ -245,7 +246,7 @@ router.post('/checkout', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.post('/change-plan', async (req, res, next) => {
|
||||
router.post('/change-plan', requireRole('OWNER'), async (req, res, next) => {
|
||||
try {
|
||||
const { plan, billingPeriod, currency } = z.object({
|
||||
plan: z.enum(['STARTER', 'GROWTH', 'PRO']),
|
||||
@@ -262,7 +263,7 @@ router.post('/change-plan', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.post('/cancel', async (req, res, next) => {
|
||||
router.post('/cancel', requireRole('OWNER'), async (req, res, next) => {
|
||||
try {
|
||||
const updated = await prisma.subscription.update({
|
||||
where: { companyId: req.companyId },
|
||||
@@ -272,7 +273,7 @@ router.post('/cancel', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.post('/resume', async (req, res, next) => {
|
||||
router.post('/resume', requireRole('OWNER'), async (req, res, next) => {
|
||||
try {
|
||||
const updated = await prisma.subscription.update({
|
||||
where: { companyId: req.companyId },
|
||||
|
||||
@@ -6,6 +6,7 @@ import { uploadImage } from '../lib/storage'
|
||||
import { requireCompanyAuth } from '../middleware/requireCompanyAuth'
|
||||
import { requireTenant } from '../middleware/requireTenant'
|
||||
import { requireSubscription } from '../middleware/requireSubscription'
|
||||
import { requireRole } from '../middleware/requireRole'
|
||||
|
||||
const router = Router()
|
||||
const upload = multer({ storage: multer.memoryStorage(), limits: { fileSize: 10 * 1024 * 1024 } })
|
||||
@@ -48,7 +49,7 @@ router.get('/', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.post('/', async (req, res, next) => {
|
||||
router.post('/', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const body = vehicleSchema.parse(req.body)
|
||||
const vehicle = await prisma.vehicle.create({ data: { ...body, companyId: req.companyId } })
|
||||
@@ -63,7 +64,7 @@ router.get('/:id', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.patch('/:id', async (req, res, next) => {
|
||||
router.patch('/:id', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const body = vehicleSchema.partial().parse(req.body)
|
||||
if (body.status === 'MAINTENANCE' || body.status === 'OUT_OF_SERVICE') {
|
||||
@@ -78,14 +79,14 @@ router.patch('/:id', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.delete('/:id', async (req, res, next) => {
|
||||
router.delete('/:id', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
await prisma.vehicle.updateMany({ where: { id: req.params.id, companyId: req.companyId }, data: { status: 'OUT_OF_SERVICE', isPublished: false } })
|
||||
res.json({ data: { success: true } })
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.post('/:id/photos', upload.array('photos', 10), async (req, res, next) => {
|
||||
router.post('/:id/photos', requireRole('MANAGER'), upload.array('photos', 10), async (req, res, next) => {
|
||||
try {
|
||||
const vehicle = await prisma.vehicle.findFirstOrThrow({ where: { id: req.params.id, companyId: req.companyId } })
|
||||
const files = req.files as Express.Multer.File[]
|
||||
@@ -95,7 +96,7 @@ router.post('/:id/photos', upload.array('photos', 10), async (req, res, next) =>
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.delete('/:id/photos/:idx', async (req, res, next) => {
|
||||
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)
|
||||
@@ -105,7 +106,7 @@ router.delete('/:id/photos/:idx', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.patch('/:id/publish', async (req, res, next) => {
|
||||
router.patch('/:id/publish', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const { isPublished } = z.object({ isPublished: z.boolean() }).parse(req.body)
|
||||
await prisma.vehicle.updateMany({ where: { id: req.params.id, companyId: req.companyId }, data: { isPublished } })
|
||||
@@ -214,7 +215,7 @@ router.get('/:id/calendar', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.post('/:id/calendar/blocks', async (req, res, next) => {
|
||||
router.post('/:id/calendar/blocks', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const body = z.object({
|
||||
startDate: z.string().datetime({ offset: true }).or(z.string().regex(/^\d{4}-\d{2}-\d{2}$/)),
|
||||
@@ -242,7 +243,7 @@ router.post('/:id/calendar/blocks', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.delete('/:id/calendar/blocks/:blockId', async (req, res, next) => {
|
||||
router.delete('/:id/calendar/blocks/:blockId', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
await prisma.vehicle.findFirstOrThrow({ where: { id: req.params.id, companyId: req.companyId } })
|
||||
await prisma.vehicleCalendarBlock.deleteMany({
|
||||
@@ -259,7 +260,7 @@ router.get('/:id/maintenance', async (req, res, next) => {
|
||||
} catch (err) { next(err) }
|
||||
})
|
||||
|
||||
router.post('/:id/maintenance', async (req, res, next) => {
|
||||
router.post('/:id/maintenance', requireRole('MANAGER'), async (req, res, next) => {
|
||||
try {
|
||||
const body = z.object({
|
||||
type: z.string().min(1),
|
||||
|
||||
Reference in New Issue
Block a user