Files
alrahma_sunday_school_api/apps/api/dist/modules/admin/admin.repo.js
T
2026-06-11 03:22:12 -04:00

523 lines
20 KiB
JavaScript

"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