"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.findAdminByEmail = findAdminByEmail; exports.findAdminByIdOrThrow = findAdminByIdOrThrow; exports.updateAdminLastLogin = updateAdminLastLogin; exports.updateAdminTotpSecret = updateAdminTotpSecret; exports.enableAdminTotp = enableAdminTotp; exports.replaceAdminRecoveryCodes = replaceAdminRecoveryCodes; exports.listUnusedAdminRecoveryCodes = listUnusedAdminRecoveryCodes; exports.markAdminRecoveryCodeUsed = markAdminRecoveryCodeUsed; exports.setAdminPasswordReset = setAdminPasswordReset; exports.findAdminByResetToken = findAdminByResetToken; exports.updateAdminPassword = updateAdminPassword; exports.createAuditLog = createAuditLog; exports.listCompaniesPage = listCompaniesPage; exports.getCompanyDetail = getCompanyDetail; exports.getCompanyUpdateSnapshot = getCompanyUpdateSnapshot; exports.applyCompanyUpdate = applyCompanyUpdate; exports.updateCompanyStatus = updateCompanyStatus; exports.deleteCompany = deleteCompany; exports.getCompanyForImpersonation = getCompanyForImpersonation; exports.listRentersPage = listRentersPage; exports.updateRenterActive = updateRenterActive; exports.getPlatformMetricCounts = getPlatformMetricCounts; exports.listAuditLogsPage = listAuditLogsPage; exports.listAdmins = listAdmins; exports.createAdmin = createAdmin; exports.updateAdminRole = updateAdminRole; exports.updateAdmin = updateAdmin; exports.replaceAdminPermissions = replaceAdminPermissions; exports.listBillingPage = listBillingPage; exports.listActiveSubscriptionsForMrr = listActiveSubscriptionsForMrr; exports.getBillingStatusCounts = getBillingStatusCounts; exports.listCompanyInvoicesPage = listCompanyInvoicesPage; exports.getInvoicePdfRecord = getInvoicePdfRecord; exports.listPricingConfigs = listPricingConfigs; exports.upsertPricingConfig = upsertPricingConfig; exports.listPlanFeatures = listPlanFeatures; exports.createPlanFeature = createPlanFeature; exports.updatePlanFeature = updatePlanFeature; exports.deletePlanFeature = deletePlanFeature; exports.listPromotions = listPromotions; exports.createPromotion = createPromotion; exports.updatePromotion = updatePromotion; exports.deletePromotion = deletePromotion; exports.listNotificationsPage = listNotificationsPage; const prisma_1 = require("../../lib/prisma"); const companyListInclude = { brand: { select: { displayName: true, logoUrl: true, subdomain: true } }, contractSettings: { select: { legalName: true } }, subscription: { select: { plan: true, status: true } }, _count: { select: { employees: true, vehicles: true } }, }; const companyDetailInclude = { brand: true, contractSettings: true, accountingSettings: true, subscription: { include: { invoices: { orderBy: { createdAt: 'desc' }, take: 10 } } }, employees: true, _count: { select: { employees: true, vehicles: true, customers: true, reservations: true } }, }; const billingInclude = { company: { select: { id: true, name: true, email: true, slug: true, status: true } }, invoices: { select: { id: true, amount: true, currency: true, status: true, paidAt: true, createdAt: true }, orderBy: { createdAt: 'desc' }, take: 5, }, _count: { select: { invoices: true } }, }; function parseOptionalDate(value) { if (!value) return null; return new Date(value); } function findAdminByEmail(email) { return prisma_1.prisma.adminUser.findFirst({ where: { email: { equals: email, mode: 'insensitive', }, }, }); } function findAdminByIdOrThrow(id) { return prisma_1.prisma.adminUser.findUniqueOrThrow({ where: { id } }); } function updateAdminLastLogin(id) { return prisma_1.prisma.adminUser.update({ where: { id }, data: { lastLoginAt: new Date() } }); } function updateAdminTotpSecret(id, secret) { return prisma_1.prisma.adminUser.update({ where: { id }, data: { totpSecret: secret } }); } function enableAdminTotp(id) { return prisma_1.prisma.adminUser.update({ where: { id }, data: { totpEnabled: true } }); } async function replaceAdminRecoveryCodes(adminUserId, codeHashes) { return prisma_1.prisma.$transaction(async (tx) => { await tx.adminRecoveryCode.deleteMany({ where: { adminUserId } }); await tx.adminRecoveryCode.createMany({ data: codeHashes.map((codeHash) => ({ adminUserId, codeHash })), }); }); } function listUnusedAdminRecoveryCodes(adminUserId) { return prisma_1.prisma.adminRecoveryCode.findMany({ where: { adminUserId, usedAt: null }, select: { id: true, codeHash: true }, orderBy: { createdAt: 'asc' }, }); } function markAdminRecoveryCodeUsed(id) { return prisma_1.prisma.adminRecoveryCode.update({ where: { id }, data: { usedAt: new Date() } }); } function setAdminPasswordReset(id, token, expiresAt) { return prisma_1.prisma.adminUser.update({ where: { id }, data: { passwordResetToken: token, passwordResetExpiresAt: expiresAt }, }); } function findAdminByResetToken(token) { return prisma_1.prisma.adminUser.findFirst({ where: { passwordResetToken: token, passwordResetExpiresAt: { gt: new Date() }, }, }); } function updateAdminPassword(id, passwordHash) { return prisma_1.prisma.adminUser.update({ where: { id }, data: { passwordHash, passwordResetToken: null, passwordResetExpiresAt: null, }, }); } function createAuditLog(data) { return prisma_1.prisma.auditLog.create({ data: data }); } async function listCompaniesPage(query) { const where = {}; if (query.status) where.status = query.status; if (query.q) { where.OR = [ { name: { contains: query.q, mode: 'insensitive' } }, { email: { contains: query.q, mode: 'insensitive' } }, { slug: { contains: query.q, mode: 'insensitive' } }, ]; } if (query.plan) where.subscription = { plan: query.plan }; const [data, total] = await Promise.all([ prisma_1.prisma.company.findMany({ where, include: companyListInclude, skip: (query.page - 1) * query.pageSize, take: query.pageSize, orderBy: { createdAt: 'desc' }, }), prisma_1.prisma.company.count({ where }), ]); return { data, total }; } function getCompanyDetail(id) { return prisma_1.prisma.company.findUniqueOrThrow({ where: { id }, include: companyDetailInclude }); } function getCompanyUpdateSnapshot(id) { return prisma_1.prisma.company.findUniqueOrThrow({ where: { id }, include: { brand: true, contractSettings: true, accountingSettings: true, subscription: true }, }); } async function applyCompanyUpdate(id, body, current) { return prisma_1.prisma.$transaction(async (tx) => { if (body.company) { const companyData = { ...body.company }; if (companyData.address && typeof companyData.address === 'object' && !Array.isArray(companyData.address)) { const baseAddress = current.address && typeof current.address === 'object' && !Array.isArray(current.address) ? current.address : {}; companyData.address = { ...baseAddress, ...companyData.address }; } await tx.company.update({ where: { id }, data: companyData }); } if (body.subscription) { const sub = body.subscription; await tx.subscription.upsert({ where: { companyId: id }, update: { ...sub, trialStartAt: parseOptionalDate(sub.trialStartAt), trialEndAt: parseOptionalDate(sub.trialEndAt), currentPeriodStart: parseOptionalDate(sub.currentPeriodStart), currentPeriodEnd: parseOptionalDate(sub.currentPeriodEnd), cancelledAt: parseOptionalDate(sub.cancelledAt), }, create: { companyId: id, plan: sub.plan ?? 'STARTER', billingPeriod: sub.billingPeriod ?? 'MONTHLY', status: sub.status ?? 'TRIALING', currency: sub.currency ?? 'MAD', trialStartAt: parseOptionalDate(sub.trialStartAt), trialEndAt: parseOptionalDate(sub.trialEndAt), currentPeriodStart: parseOptionalDate(sub.currentPeriodStart), currentPeriodEnd: parseOptionalDate(sub.currentPeriodEnd), cancelledAt: parseOptionalDate(sub.cancelledAt), cancelAtPeriodEnd: sub.cancelAtPeriodEnd ?? false, }, }); } if (body.brand) { await tx.brandSettings.upsert({ where: { companyId: id }, update: body.brand, create: { companyId: id, displayName: body.brand.displayName ?? current.name, subdomain: body.brand.subdomain ?? current.slug, paymentMethodsEnabled: current.brand?.paymentMethodsEnabled ?? [], ...body.brand, }, }); } if (body.contractSettings) { await tx.contractSettings.upsert({ where: { companyId: id }, update: body.contractSettings, create: { companyId: id, ...body.contractSettings }, }); } if (body.accountingSettings) { await tx.accountingSettings.upsert({ where: { companyId: id }, update: body.accountingSettings, create: { companyId: id, ...body.accountingSettings }, }); } return tx.company.findUniqueOrThrow({ where: { id }, include: companyDetailInclude }); }); } function updateCompanyStatus(id, status) { return prisma_1.prisma.company.update({ where: { id }, data: { status: status } }); } function deleteCompany(id) { return prisma_1.prisma.company.delete({ where: { id } }); } function getCompanyForImpersonation(id) { return prisma_1.prisma.company.findUniqueOrThrow({ where: { id }, include: { employees: { where: { role: 'OWNER' } } }, }); } async function listRentersPage(query) { const where = {}; if (query.blocked !== undefined) where.isActive = query.blocked === 'false'; if (query.q) { where.OR = [ { firstName: { contains: query.q, mode: 'insensitive' } }, { email: { contains: query.q, mode: 'insensitive' } }, ]; } const [data, total] = await Promise.all([ prisma_1.prisma.renter.findMany({ where, select: { id: true, firstName: true, lastName: true, email: true, phone: true, isActive: true, createdAt: true, _count: { select: { reservations: true } }, }, skip: (query.page - 1) * query.pageSize, take: query.pageSize, orderBy: { createdAt: 'desc' }, }), prisma_1.prisma.renter.count({ where }), ]); return { data, total }; } function updateRenterActive(id, isActive) { return prisma_1.prisma.renter.update({ where: { id }, data: { isActive } }); } async function getPlatformMetricCounts() { const [totalCompanies, activeCompanies, trialingCompanies, suspendedCompanies, totalRenters, totalReservations,] = await Promise.all([ prisma_1.prisma.company.count(), prisma_1.prisma.company.count({ where: { status: 'ACTIVE' } }), prisma_1.prisma.company.count({ where: { status: 'TRIALING' } }), prisma_1.prisma.company.count({ where: { status: 'SUSPENDED' } }), prisma_1.prisma.renter.count(), prisma_1.prisma.reservation.count(), ]); return { totalCompanies, activeCompanies, trialingCompanies, suspendedCompanies, totalRenters, totalReservations, }; } async function listAuditLogsPage(query) { const where = {}; if (query.adminId) where.adminUserId = query.adminId; if (query.action) where.action = { contains: query.action }; if (query.companyId) where.companyId = query.companyId; if (query.entityId) where.resourceId = query.entityId; const [data, total] = await Promise.all([ prisma_1.prisma.auditLog.findMany({ where, include: { adminUser: { select: { firstName: true, lastName: true, email: true } } }, skip: (query.page - 1) * query.pageSize, take: query.pageSize, orderBy: { createdAt: 'desc' }, }), prisma_1.prisma.auditLog.count({ where }), ]); return { data, total }; } function listAdmins() { return prisma_1.prisma.adminUser.findMany({ include: { permissions: true }, }); } function createAdmin(data) { return prisma_1.prisma.adminUser.create({ data: { email: data.email, firstName: data.firstName, lastName: data.lastName, role: data.role, passwordHash: data.passwordHash, permissions: data.permissions ? { create: data.permissions } : undefined, }, include: { permissions: true }, }); } function updateAdminRole(id, role) { return prisma_1.prisma.adminUser.update({ where: { id }, data: { role: role } }); } function updateAdmin(id, data) { return prisma_1.prisma.adminUser.update({ where: { id }, data: { ...(data.email !== undefined ? { email: data.email } : {}), ...(data.firstName !== undefined ? { firstName: data.firstName } : {}), ...(data.lastName !== undefined ? { lastName: data.lastName } : {}), ...(data.role !== undefined ? { role: data.role } : {}), ...(data.passwordHash !== undefined ? { passwordHash: data.passwordHash } : {}), ...(data.isActive !== undefined ? { isActive: data.isActive } : {}), }, include: { permissions: true }, }); } async function replaceAdminPermissions(id, permissions) { await prisma_1.prisma.adminUser.findUniqueOrThrow({ where: { id } }); await prisma_1.prisma.$transaction([ prisma_1.prisma.adminPermission.deleteMany({ where: { adminUserId: id } }), prisma_1.prisma.adminPermission.createMany({ data: permissions.map((permission) => ({ adminUserId: id, resource: permission.resource, actions: permission.actions, })), }), ]); return prisma_1.prisma.adminUser.findUniqueOrThrow({ where: { id }, include: { permissions: true } }); } async function listBillingPage(query) { const where = {}; if (query.status) where.status = query.status; if (query.plan) where.plan = query.plan; const [data, total] = await Promise.all([ prisma_1.prisma.subscription.findMany({ where, include: billingInclude, skip: (query.page - 1) * query.pageSize, take: query.pageSize, orderBy: { createdAt: 'desc' }, }), prisma_1.prisma.subscription.count({ where }), ]); return { data, total }; } function listActiveSubscriptionsForMrr() { return prisma_1.prisma.subscription.findMany({ where: { status: { in: ['ACTIVE', 'TRIALING'] } }, select: { plan: true, billingPeriod: true }, }); } async function getBillingStatusCounts() { const [activeCount, trialingCount, pastDueCount, cancelledCount] = await Promise.all([ prisma_1.prisma.subscription.count({ where: { status: 'ACTIVE' } }), prisma_1.prisma.subscription.count({ where: { status: 'TRIALING' } }), prisma_1.prisma.subscription.count({ where: { status: 'PAST_DUE' } }), prisma_1.prisma.subscription.count({ where: { status: 'CANCELLED' } }), ]); return { activeCount, trialingCount, pastDueCount, cancelledCount }; } async function listCompanyInvoicesPage(companyId, query) { const [data, total] = await Promise.all([ prisma_1.prisma.subscriptionInvoice.findMany({ where: { companyId }, orderBy: { createdAt: 'desc' }, skip: (query.page - 1) * query.pageSize, take: query.pageSize, }), prisma_1.prisma.subscriptionInvoice.count({ where: { companyId } }), ]); return { data, total }; } function getInvoicePdfRecord(invoiceId) { return prisma_1.prisma.subscriptionInvoice.findUniqueOrThrow({ where: { id: invoiceId }, include: { company: { select: { name: true, email: true, phone: true, address: true } }, subscription: { select: { plan: true, billingPeriod: true, currency: true, currentPeriodStart: true, currentPeriodEnd: true, }, }, }, }); } function listPricingConfigs() { return prisma_1.prisma.pricingConfig.findMany({ orderBy: [{ plan: 'asc' }, { billingPeriod: 'asc' }] }); } function upsertPricingConfig(plan, billingPeriod, amount, updatedBy) { return prisma_1.prisma.pricingConfig.upsert({ where: { plan_billingPeriod: { plan, billingPeriod } }, update: { amount, updatedBy }, create: { id: `prc_${plan.toLowerCase()}_${billingPeriod.toLowerCase()}`, plan, billingPeriod, amount, updatedBy }, }); } function listPlanFeatures() { return prisma_1.prisma.planFeature.findMany({ orderBy: [{ plan: 'asc' }, { sortOrder: 'asc' }, { createdAt: 'asc' }], }); } function createPlanFeature(data) { return prisma_1.prisma.planFeature.create({ data: { plan: data.plan, label: data.label, sortOrder: data.sortOrder ?? 0, }, }); } function updatePlanFeature(id, data) { return prisma_1.prisma.planFeature.update({ where: { id }, data, }); } function deletePlanFeature(id) { return prisma_1.prisma.planFeature.delete({ where: { id } }); } // ─── Pricing promotions ──────────────────────────────────────────────────── function listPromotions() { return prisma_1.prisma.pricingPromotion.findMany({ orderBy: { createdAt: 'desc' } }); } function createPromotion(data) { return prisma_1.prisma.pricingPromotion.create({ data: { ...data, validFrom: new Date(data.validFrom), validUntil: data.validUntil ? new Date(data.validUntil) : null, }, }); } function updatePromotion(id, data) { const { validFrom, validUntil, ...rest } = data; return prisma_1.prisma.pricingPromotion.update({ where: { id }, data: { ...rest, ...(validFrom ? { validFrom: new Date(validFrom) } : {}), ...(validUntil !== undefined ? { validUntil: validUntil ? new Date(validUntil) : null } : {}), }, }); } function deletePromotion(id) { return prisma_1.prisma.pricingPromotion.delete({ where: { id } }); } async function listNotificationsPage(query) { const where = {}; if (query.channel) where.channel = query.channel; if (query.status) where.status = query.status; if (query.companyId) where.companyId = query.companyId; const [data, total] = await Promise.all([ prisma_1.prisma.notification.findMany({ where, orderBy: { createdAt: 'desc' }, skip: (query.page - 1) * query.pageSize, take: query.pageSize, include: { company: { select: { name: true } } }, }), prisma_1.prisma.notification.count({ where }), ]); return { data, total }; } //# sourceMappingURL=admin.repo.js.map