feat(MED-97): update benefit stats view in dashboards
This commit is contained in:
@@ -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;
|
||||
})(),
|
||||
}
|
||||
}
|
||||
@@ -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),
|
||||
},
|
||||
};
|
||||
};
|
||||
@@ -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),
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user