first commit
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
import { connect } from "mongoose";
|
||||
import EmployeesList from "../../Models/Employees/Employee";
|
||||
import { EmployeeRoles } from "../../Models/Employees/Employees.Interface";
|
||||
import AppointmentList from "../../Models/Appointments/Appointments";
|
||||
import { DashboardFinancialsResult, DashboardSummaryResult, GetDashboardFinancialsParams, IncomeDataPoint } from "./Dashboard.Interface";
|
||||
import dayjs from "dayjs";
|
||||
import { AppointmentEventByClient } from "../../Models/Appointments/Appointments.Interface";
|
||||
import { validatePermissionsByCompany, validateSessionUser } from "../../helpers/check";
|
||||
import CashFlowList from "../../Models/CashFlow/CashFlow";
|
||||
import CompaniesList from "../../Models/Companies/Companies";
|
||||
import PlanSubscriptionsList from "../../Models/PlanSubscriptions/PlanSubscriptons";
|
||||
import MetricsList from "../../Models/Metrics/Metrics";
|
||||
|
||||
export class DashboardService {
|
||||
public async getDashboardSummary(sessionUser: string): Promise<DashboardSummaryResult> {
|
||||
await connect(`${process.env.DATABASE_CONNECTION}`);
|
||||
|
||||
await validateSessionUser({ sessionUser });
|
||||
|
||||
// 1. Encontrar todas las relaciones de empleado para este usuario
|
||||
const employeeRecords = await EmployeesList.employees.find({ userId: sessionUser });
|
||||
|
||||
let finalRole: "ADMIN" | "EMPLOYEE" | "NONE" = "NONE";
|
||||
let allPersonalAgenda: AppointmentEventByClient[] = [];
|
||||
|
||||
for (const emp of employeeRecords) {
|
||||
const isAdmin = emp.roles?.includes(EmployeeRoles.ADMIN) || false;
|
||||
if (isAdmin && finalRole !== "ADMIN") {
|
||||
finalRole = "ADMIN";
|
||||
} else if (!isAdmin && finalRole === "NONE") {
|
||||
finalRole = "EMPLOYEE";
|
||||
}
|
||||
|
||||
const todayStart = dayjs().startOf("day").toDate();
|
||||
const todayEnd = dayjs().endOf("day").toDate();
|
||||
|
||||
if (isAdmin) {
|
||||
// If ADMIN, fetch all appointments for this company for today
|
||||
const apps = await AppointmentList.Appointments.AppointmentList.find({
|
||||
companyId: emp.companyId,
|
||||
start: { $gte: todayStart, $lte: todayEnd }
|
||||
});
|
||||
for (const a of apps) {
|
||||
try {
|
||||
const evt = await AppointmentList.getAppointmentEvent({
|
||||
appointmentId: String(a._id),
|
||||
sessionUser: sessionUser
|
||||
});
|
||||
allPersonalAgenda.push(evt);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// If EMPLOYEE, fetch only their appointments for today
|
||||
const apps = await AppointmentList.Appointments.AppointmentList.find({
|
||||
companyId: emp.companyId,
|
||||
employeeId: String(emp.id),
|
||||
start: { $gte: todayStart, $lte: todayEnd }
|
||||
});
|
||||
for (const a of apps) {
|
||||
try {
|
||||
const evt = await AppointmentList.getAppointmentEvent({
|
||||
appointmentId: String(a._id),
|
||||
sessionUser: sessionUser
|
||||
});
|
||||
allPersonalAgenda.push(evt);
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sort agenda by start time
|
||||
allPersonalAgenda.sort((a, b) => a.startTime - b.startTime);
|
||||
|
||||
// Note: globalMetrics is handled by the frontend useSessionStore
|
||||
// we just return the role and the personalAgenda
|
||||
return {
|
||||
role: finalRole,
|
||||
personalAgenda: allPersonalAgenda
|
||||
};
|
||||
}
|
||||
|
||||
public async getDashboardFinancials(params: GetDashboardFinancialsParams): Promise<DashboardFinancialsResult> {
|
||||
await connect(`${process.env.DATABASE_CONNECTION}`);
|
||||
|
||||
await validateSessionUser({ sessionUser: params.sessionUser });
|
||||
await validatePermissionsByCompany({ companyId: params.companyId, sessionUser: params.sessionUser });
|
||||
|
||||
const now = dayjs();
|
||||
let startDate: Date;
|
||||
let prevStartDate: Date;
|
||||
let endDate = now.toDate();
|
||||
let prevEndDate: Date;
|
||||
|
||||
if (params.timeframe === "week") {
|
||||
startDate = now.subtract(7, "day").startOf("day").toDate();
|
||||
prevStartDate = now.subtract(14, "day").startOf("day").toDate();
|
||||
prevEndDate = now.subtract(7, "day").endOf("day").toDate();
|
||||
} else if (params.timeframe === "month") {
|
||||
startDate = now.subtract(1, "month").startOf("day").toDate();
|
||||
prevStartDate = now.subtract(2, "month").startOf("day").toDate();
|
||||
prevEndDate = now.subtract(1, "month").endOf("day").toDate();
|
||||
} else { // year
|
||||
startDate = now.subtract(1, "year").startOf("month").toDate();
|
||||
prevStartDate = now.subtract(2, "year").startOf("month").toDate();
|
||||
prevEndDate = now.subtract(1, "year").endOf("month").toDate();
|
||||
}
|
||||
|
||||
// Fetch current period cashflow
|
||||
const currentMatch: any = {
|
||||
companyId: params.companyId,
|
||||
type: "deposit",
|
||||
createdAt: { $gte: startDate, $lte: endDate }
|
||||
};
|
||||
if (params.employeeId) currentMatch.employeeId = params.employeeId;
|
||||
|
||||
const currentMovements = await CashFlowList.movements.movementList.find(currentMatch);
|
||||
|
||||
// Fetch previous period cashflow
|
||||
const prevMatch: any = {
|
||||
companyId: params.companyId,
|
||||
type: "deposit",
|
||||
createdAt: { $gte: prevStartDate, $lte: prevEndDate }
|
||||
};
|
||||
if (params.employeeId) prevMatch.employeeId = params.employeeId;
|
||||
|
||||
const prevMovements = await CashFlowList.movements.movementList.find(prevMatch);
|
||||
|
||||
const currentPeriodTotal = currentMovements.reduce((sum, m) => sum + m.amount, 0);
|
||||
const previousPeriodTotal = prevMovements.reduce((sum, m) => sum + m.amount, 0);
|
||||
|
||||
// Group data points
|
||||
const dataPointsMap = new Map<string, number>();
|
||||
|
||||
currentMovements.forEach(m => {
|
||||
let key = "";
|
||||
if (params.timeframe === "year") {
|
||||
key = dayjs(m.createdAt).format("YYYY-MM");
|
||||
} else {
|
||||
key = dayjs(m.createdAt).format("YYYY-MM-DD");
|
||||
}
|
||||
dataPointsMap.set(key, (dataPointsMap.get(key) || 0) + m.amount);
|
||||
});
|
||||
|
||||
// Fill empty dates for the chart
|
||||
const currentPeriodData: IncomeDataPoint[] = [];
|
||||
if (params.timeframe === "year") {
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const k = dayjs(startDate).add(i, "month").format("YYYY-MM");
|
||||
currentPeriodData.push({ date: k, amount: dataPointsMap.get(k) || 0 });
|
||||
}
|
||||
} else {
|
||||
const days = params.timeframe === "week" ? 7 : 30; // Approx
|
||||
for (let i = 0; i <= days; i++) {
|
||||
const k = dayjs(startDate).add(i, "day").format("YYYY-MM-DD");
|
||||
if (dayjs(k).isAfter(now)) break;
|
||||
currentPeriodData.push({ date: k, amount: dataPointsMap.get(k) || 0 });
|
||||
}
|
||||
}
|
||||
|
||||
// Calculate unpaid today
|
||||
const todayStart = now.startOf("day").toDate();
|
||||
const todayEnd = now.endOf("day").toDate();
|
||||
|
||||
const unpaidMatch: any = {
|
||||
companyId: params.companyId,
|
||||
payment: false,
|
||||
start: { $gte: todayStart, $lte: todayEnd }
|
||||
};
|
||||
if (params.employeeId) unpaidMatch.employeeId = params.employeeId;
|
||||
|
||||
const unpaidApps = await AppointmentList.Appointments.AppointmentList.find(unpaidMatch);
|
||||
const unpaidToday = unpaidApps.reduce((sum, a) => sum + (a.price || 0), 0);
|
||||
|
||||
return {
|
||||
currentPeriodTotal,
|
||||
previousPeriodTotal,
|
||||
currentPeriodData,
|
||||
unpaidToday
|
||||
};
|
||||
}
|
||||
|
||||
public async getCompanyMetrics(params: { sessionUser: string; companyId: string }): Promise<any> {
|
||||
await connect(`${process.env.DATABASE_CONNECTION}`);
|
||||
|
||||
await validateSessionUser({ sessionUser: params.sessionUser });
|
||||
await validatePermissionsByCompany({ companyId: params.companyId, sessionUser: params.sessionUser });
|
||||
|
||||
const company = await CompaniesList.companies.findOne({ _id: params.companyId });
|
||||
if (!company) {
|
||||
throw new Error("No se encontro la compañia.");
|
||||
}
|
||||
|
||||
const ownerId = company.ownerId;
|
||||
const isOwner = String(ownerId) === String(params.sessionUser);
|
||||
|
||||
// Fetch metrics for owner
|
||||
const metrics = await MetricsList.getMetrics(String(ownerId));
|
||||
|
||||
// Fetch subscription for owner
|
||||
const subscription = await PlanSubscriptionsList.getSubscriptionByUser({ sessionUser: String(ownerId) });
|
||||
|
||||
return {
|
||||
metrics,
|
||||
subscription,
|
||||
isOwner
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user