feat(MED-97): update benefit stats view in dashboards

This commit is contained in:
2025-09-26 13:47:32 +03:00
parent fdc2e3e064
commit 1aeee0bc30
23 changed files with 518 additions and 374 deletions

View File

@@ -0,0 +1,75 @@
import { getSupabaseServerClient } from "@/packages/supabase/src/clients/server-client";
import { loadAccountBenefitStatistics, loadCompanyPersonalAccountsBalanceEntries } from "./load-team-account-benefit-statistics";
export interface TeamAccountBenefitExpensesOverview {
benefitAmount: number | null;
benefitOccurrence: 'yearly' | 'monthly' | 'quarterly' | null;
currentMonthUsageTotal: number;
managementFee: number;
managementFeeTotal: number;
total: number;
}
const MANAGEMENT_FEE = 5.50;
const MONTHS = 12;
const QUARTERS = 4;
export async function loadTeamAccountBenefitExpensesOverview({
companyId,
employeeCount,
}: {
companyId: string;
employeeCount: number;
}): Promise<TeamAccountBenefitExpensesOverview> {
const supabase = getSupabaseServerClient();
const { data, error } = await supabase
.schema('medreport')
.from('benefit_distribution_schedule')
.select('*')
.eq('company_id', companyId)
.eq('is_active', true)
.single();
let benefitAmount: TeamAccountBenefitExpensesOverview['benefitAmount'] = null;
let benefitOccurrence: TeamAccountBenefitExpensesOverview['benefitOccurrence'] = null;
if (error) {
console.warn('Failed to load team account benefit expenses overview');
} else {
benefitAmount = data.benefit_amount as TeamAccountBenefitExpensesOverview['benefitAmount'];
benefitOccurrence = data.benefit_occurrence as TeamAccountBenefitExpensesOverview['benefitOccurrence'];
}
const { purchaseEntriesTotal } = await loadCompanyPersonalAccountsBalanceEntries({ accountId: companyId });
return {
benefitAmount,
benefitOccurrence,
currentMonthUsageTotal: purchaseEntriesTotal,
managementFee: MANAGEMENT_FEE,
managementFeeTotal: MANAGEMENT_FEE * employeeCount,
total: (() => {
if (typeof benefitAmount !== 'number') {
return 0;
}
const currentDate = new Date();
const createdAt = new Date(data.created_at);
const isCreatedThisYear = createdAt.getFullYear() === currentDate.getFullYear();
if (benefitOccurrence === 'yearly') {
return benefitAmount * employeeCount;
} else if (benefitOccurrence === 'monthly') {
const monthsLeft = isCreatedThisYear
? MONTHS - createdAt.getMonth()
: MONTHS;
return benefitAmount * employeeCount * monthsLeft;
} else if (benefitOccurrence === 'quarterly') {
const quartersLeft = isCreatedThisYear
? QUARTERS - (createdAt.getMonth() / 3)
: QUARTERS;
return benefitAmount * employeeCount * quartersLeft;
}
return 0;
})(),
}
}

View File

@@ -0,0 +1,96 @@
'use server';
import { getSupabaseServerAdminClient } from '@kit/supabase/server-admin-client';
export interface AccountBenefitStatistics {
benefitDistributionSchedule: {
amount: number;
};
companyAccountsCount: number;
periodTotal: number;
orders: {
totalSum: number;
analysesCount: number;
analysesSum: number;
analysisPackagesCount: number;
analysisPackagesSum: number;
}
}
export const loadCompanyPersonalAccountsBalanceEntries = async ({
accountId,
}: {
accountId: string;
}) => {
const supabase = getSupabaseServerAdminClient();
const { count, data: accountMemberships } = await supabase
.schema('medreport')
.from('accounts_memberships')
.select('user_id')
.eq('account_id', accountId)
.throwOnError();
const { data: accountBalanceEntries } = await supabase
.schema('medreport')
.from('account_balance_entries')
.select('*')
.eq('is_active', true)
.in('account_id', accountMemberships.map(({ user_id }) => user_id))
.throwOnError();
const purchaseEntries = accountBalanceEntries.filter(({ entry_type }) => entry_type === 'purchase');
const analysesEntries = purchaseEntries.filter(({ is_analysis_order }) => is_analysis_order);
const analysisPackagesEntries = purchaseEntries.filter(({ is_analysis_package_order }) => is_analysis_package_order);
return {
accountBalanceEntries,
analysesEntries,
analysisPackagesEntries,
companyAccountsCount: count || 0,
purchaseEntries,
purchaseEntriesTotal: purchaseEntries.reduce((acc, { amount }) => acc + Math.abs(amount || 0), 0),
};
}
export const loadAccountBenefitStatistics = async (
accountId: string,
): Promise<AccountBenefitStatistics> => {
const supabase = getSupabaseServerAdminClient();
const {
analysesEntries,
analysisPackagesEntries,
companyAccountsCount,
purchaseEntriesTotal,
} = await loadCompanyPersonalAccountsBalanceEntries({ accountId });
const { data: benefitDistributionSchedule } = await supabase
.schema('medreport')
.from('benefit_distribution_schedule')
.select('*')
.eq('company_id', accountId)
.eq('is_active', true)
.single()
.throwOnError();
const scheduleAmount = benefitDistributionSchedule?.benefit_amount || 0;
return {
companyAccountsCount,
benefitDistributionSchedule: {
amount: benefitDistributionSchedule?.benefit_amount || 0,
},
periodTotal: scheduleAmount * companyAccountsCount,
orders: {
totalSum: purchaseEntriesTotal,
analysesCount: analysesEntries.length,
analysesSum: analysesEntries.reduce((acc, { amount }) => acc + Math.abs(amount || 0), 0),
analysisPackagesCount: analysisPackagesEntries.length,
analysisPackagesSum: analysisPackagesEntries.reduce((acc, { amount }) => acc + Math.abs(amount || 0), 0),
},
};
};

View File

@@ -11,6 +11,7 @@ import {
} from '~/lib/utils';
import { TeamAccountStatisticsProps } from '../../_components/team-account-statistics';
import type { BmiThresholds } from '@kit/accounts/types/accounts';
interface AccountHealthDetailsField {
title: string;
@@ -25,10 +26,7 @@ interface AccountHealthDetailsField {
export const getAccountHealthDetailsFields = (
memberParams: TeamAccountStatisticsProps['memberParams'],
bmiThresholds: Omit<
Database['medreport']['Tables']['bmi_thresholds']['Row'],
'id'
>[],
bmiThresholds: Omit<BmiThresholds, 'id'>[],
members: Database['medreport']['Functions']['get_account_members']['Returns'],
): AccountHealthDetailsField[] => {
const averageWeight =
@@ -82,7 +80,7 @@ export const getAccountHealthDetailsFields = (
},
{
title: 'teams:healthDetails.bmi',
value: averageBMI,
value: averageBMI!,
Icon: TrendingUp,
iconBg: getBmiBackgroundColor(bmiStatus),
},