"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); const express_1 = require("express"); const requireAdminAuth_1 = require("../../middleware/requireAdminAuth"); const validate_1 = require("../../http/validate"); const respond_1 = require("../../http/respond"); const sessionCookies_1 = require("../../security/sessionCookies"); const service = __importStar(require("./admin.service")); const subService = __importStar(require("../subscriptions/subscription.service")); const menuService = __importStar(require("../menu/menu.service")); const admin_presenter_1 = require("./admin.presenter"); const admin_schemas_1 = require("./admin.schemas"); const zod_1 = require("zod"); const adminSubOverrideSchema = zod_1.z.object({ reason: zod_1.z.string().min(1).max(500), }); const adminExtendTrialSchema = zod_1.z.object({ extraDays: zod_1.z.number().int().positive(), reason: zod_1.z.string().min(1).max(500), }); const adminImpersonationSchema = zod_1.z.object({ reason: zod_1.z.string().min(5).max(500), durationMinutes: zod_1.z.number().int().min(1).max(30).default(15), }); const subIdParamSchema = zod_1.z.object({ subscriptionId: zod_1.z.string() }); const router = (0, express_1.Router)(); // ─── Auth (public) ───────────────────────────────────────────── router.post('/auth/login', async (req, res, next) => { try { const { email, password, totpCode, recoveryCode } = (0, validate_1.parseBody)(admin_schemas_1.loginSchema, req); const result = await service.login(email, password, totpCode, recoveryCode); if (!result) return res.status(401).json({ error: 'invalid_credentials', message: 'Invalid email or password', statusCode: 401 }); if ('totpRequired' in result) return res.status(401).json({ error: 'totp_required', message: '2FA code required', statusCode: 401 }); if ('invalidTotp' in result) return res.status(401).json({ error: 'invalid_totp', message: 'Invalid 2FA code', statusCode: 401 }); (0, sessionCookies_1.setSessionCookie)(res, 'admin', result.token, 8 * 60 * 60 * 1000); (0, respond_1.ok)(res, result); } catch (err) { next(err); } }); router.post('/auth/logout', (_req, res) => { (0, sessionCookies_1.clearSessionCookie)(res, 'admin'); (0, respond_1.ok)(res, { success: true }); }); router.post('/auth/forgot-password', async (req, res, next) => { try { const { email } = (0, validate_1.parseBody)(admin_schemas_1.forgotPasswordSchema, req); await service.forgotPassword(email); (0, respond_1.ok)(res, { message: 'If that email is registered, a reset link has been sent.' }); } catch (err) { next(err); } }); router.post('/auth/reset-password', async (req, res, next) => { try { const { token, password } = (0, validate_1.parseBody)(admin_schemas_1.resetPasswordSchema, req); const ok2 = await service.resetPassword(token, password); if (!ok2) return res.status(400).json({ error: 'invalid_token', message: 'Reset link is invalid or has expired.', statusCode: 400 }); (0, respond_1.ok)(res, { message: 'Password updated successfully. You can now sign in.' }); } catch (err) { next(err); } }); // ─── Auth (protected) ────────────────────────────────────────── router.get('/auth/me', requireAdminAuth_1.requireAdminAuth, (req, res) => { (0, respond_1.ok)(res, (0, admin_presenter_1.presentAdminUser)(req.admin)); }); router.post('/auth/2fa/setup', requireAdminAuth_1.requireAdminAuth, async (req, res, next) => { try { (0, respond_1.ok)(res, await service.setupTotp(req.admin.id, req.admin.email)); } catch (err) { next(err); } }); router.post('/auth/2fa/verify', requireAdminAuth_1.requireAdminAuth, async (req, res, next) => { try { const { code } = (0, validate_1.parseBody)(admin_schemas_1.totpVerifySchema, req); const result = await service.verifyTotp(req.admin.id, code); if (!result) return res.status(400).json({ error: 'invalid_code', message: 'Invalid 2FA code', statusCode: 400 }); (0, sessionCookies_1.setSessionCookie)(res, 'admin', result.token, 8 * 60 * 60 * 1000); (0, respond_1.ok)(res, { success: true, admin: result.admin, recoveryCodes: result.recoveryCodes }); } catch (err) { next(err); } }); router.post('/auth/2fa/recovery-codes/regenerate', requireAdminAuth_1.requireAdminAuth, requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => { try { (0, respond_1.ok)(res, await service.regenerateRecoveryCodes(req.admin.id)); } catch (err) { next(err); } }); // ─── Companies ───────────────────────────────────────────────── router.get('/companies', requireAdminAuth_1.requireAdminAuth, async (req, res, next) => { try { (0, respond_1.ok)(res, await service.listCompanies((0, validate_1.parseQuery)(admin_schemas_1.companiesQuerySchema, req))); } catch (err) { next(err); } }); router.get('/companies/:id', requireAdminAuth_1.requireAdminAuth, async (req, res, next) => { try { const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req); (0, respond_1.ok)(res, await service.getCompany(id)); } catch (err) { next(err); } }); router.patch('/companies/:id', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => { try { const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req); const body = (0, validate_1.parseBody)(admin_schemas_1.adminCompanyUpdateSchema, req); (0, respond_1.ok)(res, await service.updateCompany(id, body, req.admin.id, req.ip)); } catch (err) { next(err); } }); router.patch('/companies/:id/status', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => { try { const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req); const { status, reason } = (0, validate_1.parseBody)(admin_schemas_1.companyStatusSchema, req); (0, respond_1.ok)(res, await service.setCompanyStatus(id, status, reason, req.admin.id, req.ip)); } catch (err) { next(err); } }); router.delete('/companies/:id', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => { try { const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req); await service.deleteCompany(id, req.admin.id, req.ip); (0, respond_1.ok)(res, { success: true }); } catch (err) { next(err); } }); router.post('/companies/:id/impersonate', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPER_ADMIN'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => { try { const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req); const { reason, durationMinutes } = (0, validate_1.parseBody)(adminImpersonationSchema, req); (0, respond_1.ok)(res, await service.impersonateCompany(id, req.admin.id, req.ip, reason, durationMinutes)); } catch (err) { next(err); } }); // ─── Menu management ────────────────────────────────────────── router.get('/menu-items', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (_req, res, next) => { try { (0, respond_1.ok)(res, await menuService.listMenuItems()); } catch (err) { next(err); } }); router.post('/menu-items', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => { try { (0, respond_1.created)(res, { data: await menuService.createMenuItem((0, validate_1.parseBody)(admin_schemas_1.menuItemSchema, req), req.admin) }); } catch (err) { next(err); } }); router.get('/menu-items/:id', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => { try { const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req); (0, respond_1.ok)(res, await menuService.getMenuItem(id)); } catch (err) { next(err); } }); router.put('/menu-items/:id', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => { try { const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req); (0, respond_1.ok)(res, await menuService.updateMenuItem(id, (0, validate_1.parseBody)(admin_schemas_1.menuItemSchema, req), req.admin)); } catch (err) { next(err); } }); router.patch('/menu-items/:id/status', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => { try { const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req); const { isActive } = (0, validate_1.parseBody)(admin_schemas_1.menuItemStatusSchema, req); (0, respond_1.ok)(res, await menuService.setMenuItemStatus(id, isActive, req.admin)); } catch (err) { next(err); } }); router.delete('/menu-items/:id', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => { try { const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req); await menuService.deleteMenuItem(id, req.admin); (0, respond_1.ok)(res, { success: true }); } catch (err) { next(err); } }); router.post('/menu-items/:id/subscriptions', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => { try { const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req); const { assignments } = (0, validate_1.parseBody)(admin_schemas_1.menuPlanAssignmentsSchema, req); (0, respond_1.ok)(res, await menuService.assignMenuItemToPlans(id, assignments, req.admin)); } catch (err) { next(err); } }); router.delete('/menu-items/:id/subscriptions/:plan', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => { try { const { id, plan } = (0, validate_1.parseParams)(admin_schemas_1.menuPlanParamSchema, req); (0, respond_1.ok)(res, await menuService.removeMenuItemFromPlan(id, plan, req.admin)); } catch (err) { next(err); } }); router.post('/menu-items/:id/companies', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => { try { const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req); const { assignments } = (0, validate_1.parseBody)(admin_schemas_1.menuCompanyAssignmentsSchema, req); (0, respond_1.ok)(res, await menuService.assignMenuItemToCompanies(id, assignments, req.admin)); } catch (err) { next(err); } }); router.delete('/menu-items/:id/companies/:companyId', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => { try { const { id, companyId } = (0, validate_1.parseParams)(admin_schemas_1.menuCompanyParamSchema, req); (0, respond_1.ok)(res, await menuService.removeMenuItemFromCompany(id, companyId, req.admin)); } catch (err) { next(err); } }); router.post('/menu-preview', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => { try { (0, respond_1.ok)(res, await menuService.previewCompanyMenu((0, validate_1.parseBody)(admin_schemas_1.menuPreviewSchema, req))); } catch (err) { next(err); } }); router.get('/menu-audit-logs', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => { try { (0, respond_1.ok)(res, await menuService.listMenuAuditLogs((0, validate_1.parseQuery)(admin_schemas_1.menuAuditLogQuerySchema, req))); } catch (err) { next(err); } }); // ─── Renters ─────────────────────────────────────────────────── router.get('/renters', requireAdminAuth_1.requireAdminAuth, async (req, res, next) => { try { (0, respond_1.ok)(res, await service.listRenters((0, validate_1.parseQuery)(admin_schemas_1.rentersQuerySchema, req))); } catch (err) { next(err); } }); router.post('/renters/:id/block', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => { try { const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req); await service.setRenterActive(id, false); (0, respond_1.ok)(res, { success: true }); } catch (err) { next(err); } }); router.post('/renters/:id/unblock', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => { try { const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req); await service.setRenterActive(id, true); (0, respond_1.ok)(res, { success: true }); } catch (err) { next(err); } }); // ─── Metrics ─────────────────────────────────────────────────── router.get('/metrics', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => { try { (0, respond_1.ok)(res, await service.getPlatformMetrics()); } catch (err) { next(err); } }); // ─── Notifications ───────────────────────────────────────────── router.get('/notifications', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => { try { (0, respond_1.ok)(res, await service.listNotifications((0, validate_1.parseQuery)(admin_schemas_1.notificationsQuerySchema, req))); } catch (err) { next(err); } }); // ─── Audit logs ──────────────────────────────────────────────── router.get('/audit-logs', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('ADMIN'), async (req, res, next) => { try { (0, respond_1.ok)(res, await service.getAuditLogs((0, validate_1.parseQuery)(admin_schemas_1.auditLogQuerySchema, req))); } catch (err) { next(err); } }); // ─── Admin users ─────────────────────────────────────────────── router.get('/admins', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPER_ADMIN'), async (req, res, next) => { try { (0, respond_1.ok)(res, await service.listAdmins()); } catch (err) { next(err); } }); router.post('/admins', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPER_ADMIN'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => { try { (0, respond_1.created)(res, { data: await service.createAdmin((0, validate_1.parseBody)(admin_schemas_1.createAdminSchema, req)) }); } catch (err) { next(err); } }); router.patch('/admins/:id', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPER_ADMIN'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => { try { const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req); (0, respond_1.ok)(res, await service.updateAdmin(id, (0, validate_1.parseBody)(admin_schemas_1.updateAdminSchema, req))); } catch (err) { next(err); } }); router.patch('/admins/:id/role', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPER_ADMIN'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => { try { const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req); const { role } = (0, validate_1.parseBody)(admin_schemas_1.adminRoleSchema, req); await service.updateAdminRole(id, role); (0, respond_1.ok)(res, { success: true }); } catch (err) { next(err); } }); router.patch('/admins/:id/permissions', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPER_ADMIN'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => { try { const { id } = (0, validate_1.parseParams)(admin_schemas_1.idParamSchema, req); const { permissions } = (0, validate_1.parseBody)(admin_schemas_1.adminPermissionsSchema, req); (0, respond_1.ok)(res, await service.updateAdminPermissions(id, permissions)); } catch (err) { next(err); } }); // ─── Billing ─────────────────────────────────────────────────── router.get('/billing', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => { try { (0, respond_1.ok)(res, await service.getBilling((0, validate_1.parseQuery)(admin_schemas_1.billingQuerySchema, req))); } catch (err) { next(err); } }); router.get('/billing/invoices/:invoiceId/pdf', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => { try { const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req); const { pdfBuffer, invoiceNumber } = await service.getInvoicePdf(invoiceId); res.setHeader('Content-Type', 'application/pdf'); res.setHeader('Content-Disposition', `attachment; filename="${invoiceNumber}.pdf"`); res.setHeader('Content-Length', pdfBuffer.length); res.end(pdfBuffer); } catch (err) { next(err); } }); router.get('/billing/:companyId', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => { try { const { companyId } = (0, validate_1.parseParams)(admin_schemas_1.companyIdParamSchema, req); (0, respond_1.ok)(res, await service.getBillingAccountDetail(companyId)); } catch (err) { next(err); } }); router.get('/billing/:companyId/invoices', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => { try { const { companyId } = (0, validate_1.parseParams)(admin_schemas_1.companyIdParamSchema, req); (0, respond_1.ok)(res, await service.getCompanyInvoices(companyId, (0, validate_1.parseQuery)(admin_schemas_1.invoicesQuerySchema, req))); } catch (err) { next(err); } }); router.patch('/billing/accounts/:billingAccountId', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => { try { const { billingAccountId } = (0, validate_1.parseParams)(admin_schemas_1.billingAccountIdParamSchema, req); (0, respond_1.ok)(res, await service.updateBillingAccount(billingAccountId, (0, validate_1.parseBody)(admin_schemas_1.billingAccountUpdateSchema, req), req.admin.id, req.ip)); } catch (err) { next(err); } }); router.post('/billing/accounts/:billingAccountId/pause-dunning', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => { try { const { billingAccountId } = (0, validate_1.parseParams)(admin_schemas_1.billingAccountIdParamSchema, req); (0, respond_1.ok)(res, await service.setDunningPaused(billingAccountId, true, req.admin.id, req.ip)); } catch (err) { next(err); } }); router.post('/billing/accounts/:billingAccountId/resume-dunning', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => { try { const { billingAccountId } = (0, validate_1.parseParams)(admin_schemas_1.billingAccountIdParamSchema, req); (0, respond_1.ok)(res, await service.setDunningPaused(billingAccountId, false, req.admin.id, req.ip)); } catch (err) { next(err); } }); router.post('/billing/accounts/:billingAccountId/invoices', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => { try { const { billingAccountId } = (0, validate_1.parseParams)(admin_schemas_1.billingAccountIdParamSchema, req); (0, respond_1.created)(res, await service.createBillingInvoice(billingAccountId, (0, validate_1.parseBody)(admin_schemas_1.createBillingInvoiceSchema, req), req.admin.id, req.ip)); } catch (err) { next(err); } }); router.post('/billing/invoices/:invoiceId/finalize', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => { try { const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req); (0, respond_1.ok)(res, await service.finalizeBillingInvoice(invoiceId, req.admin.id, req.ip)); } catch (err) { next(err); } }); router.post('/billing/invoices/:invoiceId/pay', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => { try { const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req); (0, respond_1.ok)(res, await service.payBillingInvoice(invoiceId, (0, validate_1.parseBody)(admin_schemas_1.payBillingInvoiceSchema, req), req.admin.id, req.ip)); } catch (err) { next(err); } }); router.post('/billing/invoices/:invoiceId/retry-payment', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => { try { const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req); (0, respond_1.ok)(res, await service.retryBillingInvoicePayment(invoiceId, (0, validate_1.parseBody)(admin_schemas_1.retryBillingInvoiceSchema, req), req.admin.id, req.ip)); } catch (err) { next(err); } }); router.post('/billing/invoices/:invoiceId/void', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => { try { const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req); const { reason } = (0, validate_1.parseBody)(admin_schemas_1.billingReasonSchema, req); (0, respond_1.ok)(res, await service.voidBillingInvoice(invoiceId, reason, req.admin.id, req.ip)); } catch (err) { next(err); } }); router.post('/billing/invoices/:invoiceId/uncollectible', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => { try { const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req); const { reason } = (0, validate_1.parseBody)(admin_schemas_1.billingReasonSchema, req); (0, respond_1.ok)(res, await service.markBillingInvoiceUncollectible(invoiceId, reason, req.admin.id, req.ip)); } catch (err) { next(err); } }); router.post('/billing/invoices/:invoiceId/credit-notes', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => { try { const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req); (0, respond_1.ok)(res, await service.issueBillingCreditNote(invoiceId, (0, validate_1.parseBody)(admin_schemas_1.billingCreditNoteSchema, req), req.admin.id, req.ip)); } catch (err) { next(err); } }); router.post('/billing/invoices/:invoiceId/refunds', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => { try { const { invoiceId } = (0, validate_1.parseParams)(admin_schemas_1.invoiceIdParamSchema, req); (0, respond_1.ok)(res, await service.issueBillingRefund(invoiceId, (0, validate_1.parseBody)(admin_schemas_1.billingRefundSchema, req), req.admin.id, req.ip)); } catch (err) { next(err); } }); // ─── Pricing config ──────────────────────────────────────────── router.get('/pricing', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => { try { (0, respond_1.ok)(res, await service.getPricingConfigs()); } catch (err) { next(err); } }); router.patch('/pricing', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => { try { const { entries } = (0, validate_1.parseBody)(admin_schemas_1.pricingUpdateSchema, req); (0, respond_1.ok)(res, await service.updatePricingConfigs(entries, req.admin.id, req.ip)); } catch (err) { next(err); } }); router.get('/pricing/features', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (_req, res, next) => { try { (0, respond_1.ok)(res, await service.listPlanFeatures()); } catch (err) { next(err); } }); router.post('/pricing/features', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => { try { const data = (0, validate_1.parseBody)(admin_schemas_1.planFeatureCreateSchema, req); (0, respond_1.created)(res, await service.createPlanFeature(data, req.admin.id, req.ip)); } catch (err) { next(err); } }); router.patch('/pricing/features/:featureId', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => { try { const { featureId } = (0, validate_1.parseParams)(admin_schemas_1.planFeatureIdParamSchema, req); const data = (0, validate_1.parseBody)(admin_schemas_1.planFeatureUpdateSchema, req); (0, respond_1.ok)(res, await service.updatePlanFeature(featureId, data, req.admin.id, req.ip)); } catch (err) { next(err); } }); router.delete('/pricing/features/:featureId', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => { try { const { featureId } = (0, validate_1.parseParams)(admin_schemas_1.planFeatureIdParamSchema, req); await service.deletePlanFeature(featureId, req.admin.id, req.ip); (0, respond_1.ok)(res, { success: true }); } catch (err) { next(err); } }); // ─── Promotions ──────────────────────────────────────────────────────────── router.get('/pricing/promotions', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), async (req, res, next) => { try { (0, respond_1.ok)(res, await service.listPromotions()); } catch (err) { next(err); } }); router.post('/pricing/promotions', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => { try { const data = (0, validate_1.parseBody)(admin_schemas_1.promotionCreateSchema, req); (0, respond_1.created)(res, await service.createPromotion(data, req.admin.id, req.ip)); } catch (err) { next(err); } }); router.patch('/pricing/promotions/:promotionId', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => { try { const { promotionId } = (0, validate_1.parseParams)(admin_schemas_1.promotionIdParamSchema, req); const data = (0, validate_1.parseBody)(admin_schemas_1.promotionUpdateSchema, req); (0, respond_1.ok)(res, await service.updatePromotion(promotionId, data, req.admin.id, req.ip)); } catch (err) { next(err); } }); router.delete('/pricing/promotions/:promotionId', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('FINANCE'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => { try { const { promotionId } = (0, validate_1.parseParams)(admin_schemas_1.promotionIdParamSchema, req); await service.deletePromotion(promotionId, req.admin.id, req.ip); (0, respond_1.ok)(res, { success: true }); } catch (err) { next(err); } }); // ─── Subscription admin overrides ───────────────────────────── router.get('/subscriptions/:subscriptionId/events', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => { try { const { subscriptionId } = (0, validate_1.parseParams)(subIdParamSchema, req); (0, respond_1.ok)(res, await subService.getEventsBySubscriptionId(subscriptionId)); } catch (err) { next(err); } }); router.post('/subscriptions/:subscriptionId/extend-trial', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => { try { const { subscriptionId } = (0, validate_1.parseParams)(subIdParamSchema, req); const { extraDays, reason } = (0, validate_1.parseBody)(adminExtendTrialSchema, req); (0, respond_1.ok)(res, await subService.adminExtendTrial(subscriptionId, extraDays, req.admin.id, reason)); } catch (err) { next(err); } }); router.post('/subscriptions/:subscriptionId/extend-grace-period', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => { try { const { subscriptionId } = (0, validate_1.parseParams)(subIdParamSchema, req); const { reason } = (0, validate_1.parseBody)(adminSubOverrideSchema, req); (0, respond_1.ok)(res, await subService.adminExtendGracePeriod(subscriptionId, 7, req.admin.id, reason)); } catch (err) { next(err); } }); router.post('/subscriptions/:subscriptionId/suspend', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => { try { const { subscriptionId } = (0, validate_1.parseParams)(subIdParamSchema, req); const { reason } = (0, validate_1.parseBody)(adminSubOverrideSchema, req); (0, respond_1.ok)(res, await subService.adminSuspendSubscription(subscriptionId, req.admin.id, reason)); } catch (err) { next(err); } }); router.post('/subscriptions/:subscriptionId/reactivate', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => { try { const { subscriptionId } = (0, validate_1.parseParams)(subIdParamSchema, req); const { reason } = (0, validate_1.parseBody)(adminSubOverrideSchema, req); (0, respond_1.ok)(res, await subService.adminReactivateSubscription(subscriptionId, req.admin.id, reason)); } catch (err) { next(err); } }); router.post('/subscriptions/:subscriptionId/cancel', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), requireAdminAuth_1.requireFreshAdmin2FA, async (req, res, next) => { try { const { subscriptionId } = (0, validate_1.parseParams)(subIdParamSchema, req); const { reason } = (0, validate_1.parseBody)(adminSubOverrideSchema, req); (0, respond_1.ok)(res, await subService.adminCancelSubscription(subscriptionId, req.admin.id, reason)); } catch (err) { next(err); } }); // ─── Site config ─────────────────────────────────────────────── router.get('/site-config/marketplace-homepage', requireAdminAuth_1.requireAdminAuth, async (req, res, next) => { try { (0, respond_1.ok)(res, await service.getMarketplaceHomepage()); } catch (err) { next(err); } }); router.patch('/site-config/marketplace-homepage', requireAdminAuth_1.requireAdminAuth, (0, requireAdminAuth_1.requireAdminRole)('SUPPORT'), async (req, res, next) => { try { const { homepage } = (0, validate_1.parseBody)(admin_schemas_1.homepageUpdateSchema, req); (0, respond_1.ok)(res, await service.updateMarketplaceHomepage(homepage, req.admin.id, req.ip)); } catch (err) { next(err); } }); exports.default = router; //# sourceMappingURL=admin.routes.js.map