Files
AOS/src/app/api/aos/agency/[id]/reject/route.ts
T
Z User 970986fef7 feat: email integration (nodemailer) + wire into agency/license flows
- src/lib/email.ts: SMTP client with pre-built templates:
  - sendAgencyApprovedEmail (reseller approval + discount)
  - sendAgencyRejectedEmail (reseller rejection + reason)
  - sendLicenseKeyEmail (license key delivery)
  - sendTicketCreatedEmail (ticket confirmation)
- Agency approve route: sends approval email after DB update
- Agency reject route: sends rejection email with reason
- License creation route: sends license key email (fire-and-forget)
- Graceful degradation: if SMTP not configured, logs warning + continues
- nodemailer + @types/nodemailer installed
2026-10-28 22:50:42 +00:00

79 lines
2.3 KiB
TypeScript

import { NextResponse } from 'next/server'
import { db } from '@/lib/db'
import { z } from 'zod'
export const dynamic = 'force-dynamic'
const schema = z.object({
reason: z.string().min(1).max(500),
reviewedBy: z.string().optional(),
})
// PATCH /api/aos/agency/[id]/reject
// Admin rejects an agency application. Sets Company.agencyStatus = "rejected".
export async function PATCH(req: Request, { params }: { params: Promise<{ id: string }> }) {
try {
const { id } = await params
const parsed = schema.safeParse(await req.json())
if (!parsed.success) {
return NextResponse.json({ error: 'reason required', details: parsed.error.flatten() }, { status: 400 })
}
const { reason, reviewedBy } = parsed.data
const application = await db.agencyApplication.findUnique({
where: { id },
include: { company: true },
})
if (!application) {
return NextResponse.json({ error: 'application not found' }, { status: 404 })
}
const now = new Date()
await db.$transaction([
db.agencyApplication.update({
where: { id },
data: {
status: 'rejected',
rejectReason: reason,
reviewedBy: reviewedBy ?? 'admin:ui',
reviewedAt: now,
},
}),
db.company.update({
where: { id: application.companyId },
data: {
agencyStatus: 'rejected',
agencyRejectedAt: now,
agencyRejectReason: reason,
},
}),
])
await db.auditLog.create({
data: {
actor: reviewedBy ?? 'admin:ui',
action: 'agency.reject',
entity: 'AgencyApplication',
entityId: id,
after: JSON.stringify({ company: application.company.name, reason }),
hash: 'sha256:' + Math.random().toString(36).slice(2),
},
})
// Send rejection email
const { sendAgencyRejectedEmail } = await import('@/lib/email')
if (application.company.email) {
await sendAgencyRejectedEmail({
to: application.company.email,
companyName: application.company.name,
reason,
})
}
return NextResponse.json({ ok: true, status: 'rejected', reason })
} catch (err) {
const msg = err instanceof Error ? err.message : 'internal server error'
return NextResponse.json({ error: msg }, { status: 500 })
}
}