96 lines
5.8 KiB
JavaScript
96 lines
5.8 KiB
JavaScript
"use strict";
|
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
exports.getSummary = getSummary;
|
|
exports.getDashboard = getDashboard;
|
|
exports.getSources = getSources;
|
|
exports.getReport = getReport;
|
|
const prisma_1 = require("../../lib/prisma");
|
|
const financialReportService_1 = require("../../services/financialReportService");
|
|
function getRangeFromPeriod(period) {
|
|
const now = new Date();
|
|
switch (period) {
|
|
case 'WEEKLY': return { from: new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000), to: now };
|
|
case 'QUARTERLY': return { from: new Date(now.getFullYear(), now.getMonth() - 2, 1), to: now };
|
|
case 'ANNUAL': return { from: new Date(now.getFullYear(), 0, 1), to: now };
|
|
default: return { from: new Date(now.getFullYear(), now.getMonth(), 1), to: now };
|
|
}
|
|
}
|
|
function pct(current, previous) {
|
|
if (previous === 0)
|
|
return current > 0 ? 100 : 0;
|
|
return Math.round(((current - previous) / previous) * 100);
|
|
}
|
|
async function getSummary(companyId, period) {
|
|
const days = parseInt(period.replace('d', '')) || 30;
|
|
const since = new Date(Date.now() - days * 24 * 60 * 60 * 1000);
|
|
const [totalReservations, activeVehicles, totalRevenue, totalCustomers] = await Promise.all([
|
|
prisma_1.prisma.reservation.count({ where: { companyId, createdAt: { gte: since } } }),
|
|
prisma_1.prisma.vehicle.count({ where: { companyId, status: 'AVAILABLE' } }),
|
|
prisma_1.prisma.reservation.aggregate({ where: { companyId, status: { in: ['COMPLETED'] }, createdAt: { gte: since } }, _sum: { totalAmount: true } }),
|
|
prisma_1.prisma.customer.count({ where: { companyId } }),
|
|
]);
|
|
return { totalReservations, activeVehicles, totalRevenue: totalRevenue._sum.totalAmount ?? 0, totalCustomers, period };
|
|
}
|
|
async function getDashboard(companyId) {
|
|
const now = new Date();
|
|
const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);
|
|
const prevMonthStart = new Date(now.getFullYear(), now.getMonth() - 1, 1);
|
|
const prevMonthEnd = new Date(monthStart.getTime() - 1);
|
|
const [totalBookings, previousBookings, activeVehicles, previousActiveVehicles, totalCustomers, previousCustomers, monthlyRevenueAgg, previousRevenueAgg, recentReservations, sourceGroups, subscription,] = await Promise.all([
|
|
prisma_1.prisma.reservation.count({ where: { companyId, createdAt: { gte: monthStart } } }),
|
|
prisma_1.prisma.reservation.count({ where: { companyId, createdAt: { gte: prevMonthStart, lte: prevMonthEnd } } }),
|
|
prisma_1.prisma.vehicle.count({ where: { companyId, status: { in: ['AVAILABLE', 'RENTED'] } } }),
|
|
prisma_1.prisma.vehicle.count({ where: { companyId, createdAt: { lte: prevMonthEnd }, status: { in: ['AVAILABLE', 'RENTED'] } } }),
|
|
prisma_1.prisma.customer.count({ where: { companyId } }),
|
|
prisma_1.prisma.customer.count({ where: { companyId, createdAt: { lte: prevMonthEnd } } }),
|
|
prisma_1.prisma.reservation.aggregate({ where: { companyId, status: { in: ['CONFIRMED', 'ACTIVE', 'COMPLETED'] }, createdAt: { gte: monthStart } }, _sum: { totalAmount: true } }),
|
|
prisma_1.prisma.reservation.aggregate({ where: { companyId, status: { in: ['CONFIRMED', 'ACTIVE', 'COMPLETED'] }, createdAt: { gte: prevMonthStart, lte: prevMonthEnd } }, _sum: { totalAmount: true } }),
|
|
prisma_1.prisma.reservation.findMany({ where: { companyId }, include: { customer: true, vehicle: true }, orderBy: { createdAt: 'desc' }, take: 8 }),
|
|
prisma_1.prisma.reservation.groupBy({ by: ['source'], where: { companyId }, _count: { id: true }, _sum: { totalAmount: true } }),
|
|
prisma_1.prisma.subscription.findUnique({ where: { companyId } }),
|
|
]);
|
|
return {
|
|
kpis: {
|
|
totalBookings,
|
|
activeVehicles,
|
|
monthlyRevenue: monthlyRevenueAgg._sum.totalAmount ?? 0,
|
|
totalCustomers,
|
|
bookingsChange: pct(totalBookings, previousBookings),
|
|
vehiclesChange: pct(activeVehicles, previousActiveVehicles),
|
|
revenueChange: pct(monthlyRevenueAgg._sum.totalAmount ?? 0, previousRevenueAgg._sum.totalAmount ?? 0),
|
|
customersChange: pct(totalCustomers, previousCustomers),
|
|
},
|
|
recentReservations: recentReservations.map((r) => ({
|
|
id: r.id,
|
|
bookingRef: r.contractNumber ?? r.id.slice(-8).toUpperCase(),
|
|
customerName: `${r.customer.firstName} ${r.customer.lastName}`,
|
|
vehicleName: `${r.vehicle.make} ${r.vehicle.model}`,
|
|
startDate: r.startDate,
|
|
endDate: r.endDate,
|
|
status: r.status,
|
|
totalAmount: r.totalAmount,
|
|
})),
|
|
sourceBreakdown: sourceGroups.map((g) => ({
|
|
source: g.source,
|
|
count: g._count.id,
|
|
revenue: g._sum.totalAmount ?? 0,
|
|
})),
|
|
subscription: subscription ? {
|
|
status: subscription.status,
|
|
planName: subscription.plan,
|
|
trialEndsAt: subscription.trialEndAt,
|
|
} : null,
|
|
};
|
|
}
|
|
async function getSources(companyId) {
|
|
return prisma_1.prisma.reservation.groupBy({ by: ['source'], where: { companyId }, _count: { id: true } });
|
|
}
|
|
async function getReport(companyId, query) {
|
|
const accountingSettings = await prisma_1.prisma.accountingSettings.findUnique({ where: { companyId } });
|
|
const derivedRange = getRangeFromPeriod(query.period || accountingSettings?.reportingPeriod || 'MONTHLY');
|
|
const startDate = query.from ? new Date(query.from) : derivedRange.from;
|
|
const endDate = query.to ? new Date(query.to) : derivedRange.to;
|
|
const report = await (0, financialReportService_1.generateFinancialReport)(companyId, startDate, endDate);
|
|
return { report, startDate, endDate, format: query.format, csv: query.format === 'CSV' ? (0, financialReportService_1.toCsv)(report.rows) : null };
|
|
}
|
|
//# sourceMappingURL=analytics.service.js.map
|