mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 00:52:50 +00:00
211 lines
6.2 KiB
TypeScript
211 lines
6.2 KiB
TypeScript
import { Injectable } from '@nestjs/common';
|
|
|
|
import {
|
|
BOOKING_LIST_TABS,
|
|
mapStatusCountsToTabs,
|
|
} from '../bookings/booking-list-tabs.config';
|
|
import type { OverviewRangeQuery } from './dto/overview-query.dto';
|
|
import type { OverviewResponseDto } from './dto/overview-response.dto';
|
|
import type {
|
|
OverviewBillingTabDto,
|
|
OverviewBookingsTabDto,
|
|
OverviewCustomersTabDto,
|
|
OverviewOperationsTabDto,
|
|
OverviewStaffTabDto,
|
|
} from './dto/overview-tab-response.dto';
|
|
import { OVERVIEW_RANGE_DAYS } from './overview.constants';
|
|
import { OverviewRepository } from './overview.repository';
|
|
|
|
@Injectable()
|
|
export class OverviewService {
|
|
constructor(private readonly overviewRepository: OverviewRepository) {}
|
|
|
|
private mapStatusCounts(statusCounts: Record<string, number>) {
|
|
const pipelineTabs = mapStatusCountsToTabs(statusCounts);
|
|
const bookingsByPipeline = BOOKING_LIST_TABS.filter(
|
|
(tab) => tab.key !== 'all',
|
|
).map((tab) => ({
|
|
stage: tab.key,
|
|
count: pipelineTabs[tab.key],
|
|
}));
|
|
|
|
const bookingsByStatus = Object.entries(statusCounts)
|
|
.map(([status, count]) => ({ status, count }))
|
|
.sort((a, b) => b.count - a.count);
|
|
|
|
return { bookingsByPipeline, bookingsByStatus };
|
|
}
|
|
|
|
async getDashboard(range: OverviewRangeQuery = '30d'): Promise<OverviewResponseDto> {
|
|
const days = OVERVIEW_RANGE_DAYS[range];
|
|
|
|
const [
|
|
bookingKpis,
|
|
operationsKpis,
|
|
customerKpis,
|
|
billingKpis,
|
|
staffKpis,
|
|
bookingTrend,
|
|
statusCounts,
|
|
paymentTrend,
|
|
recentBookings,
|
|
] = await Promise.all([
|
|
this.overviewRepository.getBookingKpis(),
|
|
this.overviewRepository.getOperationsKpis(),
|
|
this.overviewRepository.getCustomerKpis(),
|
|
this.overviewRepository.getBillingKpis(),
|
|
this.overviewRepository.getStaffKpis(),
|
|
this.overviewRepository.getBookingTrend(days),
|
|
this.overviewRepository.getStatusCounts(),
|
|
this.overviewRepository.getPaymentTrend(days),
|
|
this.overviewRepository.getRecentBookings(8),
|
|
]);
|
|
|
|
const { bookingsByPipeline, bookingsByStatus } =
|
|
this.mapStatusCounts(statusCounts);
|
|
|
|
return {
|
|
kpis: {
|
|
bookings: bookingKpis,
|
|
operations: operationsKpis,
|
|
customers: customerKpis,
|
|
billing: billingKpis,
|
|
staff: staffKpis,
|
|
},
|
|
bookingTrend,
|
|
bookingsByStatus,
|
|
bookingsByPipeline,
|
|
paymentTrend,
|
|
recentBookings: recentBookings.map((row) => ({
|
|
...row,
|
|
createdAt: row.createdAt.toISOString(),
|
|
})),
|
|
generatedAt: new Date().toISOString(),
|
|
};
|
|
}
|
|
|
|
async getBookingsTab(range: OverviewRangeQuery = '30d'): Promise<OverviewBookingsTabDto> {
|
|
const days = OVERVIEW_RANGE_DAYS[range];
|
|
|
|
const [
|
|
kpis,
|
|
bookingTrend,
|
|
statusCounts,
|
|
bookingsByFreightType,
|
|
bookingsByCurrency,
|
|
recentBookings,
|
|
] = await Promise.all([
|
|
this.overviewRepository.getBookingKpis(),
|
|
this.overviewRepository.getBookingTrend(days),
|
|
this.overviewRepository.getStatusCounts(),
|
|
this.overviewRepository.getBookingsByFreightType(),
|
|
this.overviewRepository.getBookingsByCurrency(),
|
|
this.overviewRepository.getRecentBookings(8),
|
|
]);
|
|
|
|
const { bookingsByPipeline, bookingsByStatus } =
|
|
this.mapStatusCounts(statusCounts);
|
|
|
|
return {
|
|
kpis,
|
|
bookingTrend,
|
|
bookingsByStatus,
|
|
bookingsByPipeline,
|
|
bookingsByFreightType,
|
|
bookingsByCurrency,
|
|
recentBookings: recentBookings.map((row) => ({
|
|
...row,
|
|
createdAt: row.createdAt.toISOString(),
|
|
})),
|
|
generatedAt: new Date().toISOString(),
|
|
};
|
|
}
|
|
|
|
async getBillingTab(range: OverviewRangeQuery = '30d'): Promise<OverviewBillingTabDto> {
|
|
const days = OVERVIEW_RANGE_DAYS[range];
|
|
|
|
const [kpis, paymentTrend, paymentsByStatus, paymentsByMethod, revenueByCurrency] =
|
|
await Promise.all([
|
|
this.overviewRepository.getBillingKpis(),
|
|
this.overviewRepository.getPaymentTrend(days),
|
|
this.overviewRepository.getPaymentsByStatus(),
|
|
this.overviewRepository.getPaymentsByMethod(),
|
|
this.overviewRepository.getRevenueByCurrency(),
|
|
]);
|
|
|
|
return {
|
|
kpis,
|
|
paymentTrend,
|
|
paymentsByStatus,
|
|
paymentsByMethod,
|
|
revenueByCurrency,
|
|
generatedAt: new Date().toISOString(),
|
|
};
|
|
}
|
|
|
|
async getOperationsTab(): Promise<OverviewOperationsTabDto> {
|
|
const [
|
|
kpis,
|
|
trainStatusBreakdown,
|
|
wagonStatusBreakdown,
|
|
containerStatusBreakdown,
|
|
cargoStatusBreakdown,
|
|
] = await Promise.all([
|
|
this.overviewRepository.getOperationsKpis(),
|
|
this.overviewRepository.getTrainStatusBreakdown(),
|
|
this.overviewRepository.getWagonStatusBreakdown(),
|
|
this.overviewRepository.getContainerStatusBreakdown(),
|
|
this.overviewRepository.getCargoStatusBreakdown(),
|
|
]);
|
|
|
|
return {
|
|
kpis,
|
|
trainStatusBreakdown,
|
|
wagonStatusBreakdown,
|
|
containerStatusBreakdown,
|
|
cargoStatusBreakdown,
|
|
generatedAt: new Date().toISOString(),
|
|
};
|
|
}
|
|
|
|
async getCustomersTab(range: OverviewRangeQuery = '30d'): Promise<OverviewCustomersTabDto> {
|
|
const days = OVERVIEW_RANGE_DAYS[range];
|
|
|
|
const [kpis, customerGrowthTrend, customersByType, topCustomersByBookings] =
|
|
await Promise.all([
|
|
this.overviewRepository.getCustomerKpis(),
|
|
this.overviewRepository.getCustomerGrowthTrend(days),
|
|
this.overviewRepository.getCustomersByType(),
|
|
this.overviewRepository.getTopCustomersByBookings(8),
|
|
]);
|
|
|
|
return {
|
|
kpis,
|
|
customerGrowthTrend,
|
|
customersByType,
|
|
topCustomersByBookings,
|
|
generatedAt: new Date().toISOString(),
|
|
};
|
|
}
|
|
|
|
async getStaffTab(range: OverviewRangeQuery = '30d'): Promise<OverviewStaffTabDto> {
|
|
const days = OVERVIEW_RANGE_DAYS[range];
|
|
|
|
const [kpis, usersByStatus, employeeGrowthTrend, activeUsersBreakdown] =
|
|
await Promise.all([
|
|
this.overviewRepository.getStaffKpis(),
|
|
this.overviewRepository.getUsersByStatus(),
|
|
this.overviewRepository.getEmployeeGrowthTrend(days),
|
|
this.overviewRepository.getActiveUsersBreakdown(),
|
|
]);
|
|
|
|
return {
|
|
kpis,
|
|
usersByStatus,
|
|
employeeGrowthTrend,
|
|
activeUsersBreakdown,
|
|
generatedAt: new Date().toISOString(),
|
|
};
|
|
}
|
|
}
|