Merge pull request #116 from MR-medreport/MED-171

feat(MED-171): update benefits info in company members table
This commit is contained in:
2025-10-01 01:49:16 +03:00
committed by GitHub
8 changed files with 143 additions and 34 deletions

View File

@@ -63,7 +63,20 @@ async function loadAccountMembers(
throw error; throw error;
} }
return data ?? []; const members = data ?? [];
return members
.sort((prev, next) => {
if (prev.primary_owner_user_id === prev.user_id) {
return -1;
}
if (prev.role_hierarchy_level < next.role_hierarchy_level) {
return -1;
}
return 1;
});
} }
export async function loadAccountMembersBenefitsUsage( export async function loadAccountMembersBenefitsUsage(
@@ -73,6 +86,7 @@ export async function loadAccountMembersBenefitsUsage(
{ {
personal_account_id: string; personal_account_id: string;
benefit_amount: number; benefit_amount: number;
benefit_unused_amount: number;
}[] }[]
> { > {
const { data, error } = await client const { data, error } = await client
@@ -86,7 +100,11 @@ export async function loadAccountMembersBenefitsUsage(
return []; return [];
} }
return data ?? []; return (data ?? []) as unknown as {
personal_account_id: string;
benefit_amount: number;
benefit_unused_amount: number;
}[];
} }
/** /**

View File

@@ -46,6 +46,7 @@ type AccountMembersTableProps = {
membersBenefitsUsage: { membersBenefitsUsage: {
personal_account_id: string; personal_account_id: string;
benefit_amount: number; benefit_amount: number;
benefit_unused_amount: number;
}[]; }[];
}; };
@@ -82,33 +83,23 @@ export function AccountMembersTable({
membersBenefitsUsage, membersBenefitsUsage,
}); });
const filteredMembers = members const searchString = search.toLowerCase();
.filter((member) => { const filteredMembers = searchString.length > 0
const searchString = search.toLowerCase(); ? members
.filter((member) => {
const displayName = (
member.name ??
member.email.split('@')[0] ??
''
).toLowerCase();
const displayName = ( return (
member.name ?? displayName.includes(searchString) ||
member.email.split('@')[0] ?? member.role.toLowerCase().includes(searchString) ||
'' (member.personal_code || '').includes(searchString)
).toLowerCase(); );
})
return ( : members;
displayName.includes(searchString) ||
member.role.toLowerCase().includes(searchString) ||
(member.personal_code || '').includes(searchString)
);
})
.sort((prev, next) => {
if (prev.primary_owner_user_id === prev.user_id) {
return -1;
}
if (prev.role_hierarchy_level < next.role_hierarchy_level) {
return -1;
}
return 1;
});
return ( return (
<div className={'flex flex-col space-y-2'}> <div className={'flex flex-col space-y-2'}>
@@ -132,6 +123,7 @@ function useGetColumns(
membersBenefitsUsage: { membersBenefitsUsage: {
personal_account_id: string; personal_account_id: string;
benefit_amount: number; benefit_amount: number;
benefit_unused_amount: number;
}[]; }[];
}, },
): ColumnDef<Members[0]>[] { ): ColumnDef<Members[0]>[] {
@@ -185,11 +177,11 @@ function useGetColumns(
{ {
header: t('distributedBenefitsAmount'), header: t('distributedBenefitsAmount'),
cell: ({ row }) => { cell: ({ row }) => {
const benefitAmount = params.membersBenefitsUsage.find( let benefitAmount = params.membersBenefitsUsage.find(
(usage) => usage.personal_account_id === row.original.id, (usage) => usage.personal_account_id === row.original.id,
)?.benefit_amount; )?.benefit_amount;
if (typeof benefitAmount !== 'number') { if (typeof benefitAmount !== 'number') {
return '-'; benefitAmount = 0;
} }
return formatCurrency({ return formatCurrency({
@@ -199,6 +191,23 @@ function useGetColumns(
}); });
}, },
}, },
{
header: t('distributedBenefitsUnusedAmount'),
cell: ({ row }) => {
let benefitUnusedAmount = params.membersBenefitsUsage.find(
(usage) => usage.personal_account_id === row.original.id,
)?.benefit_unused_amount;
if (typeof benefitUnusedAmount !== 'number') {
benefitUnusedAmount = 0;
}
return formatCurrency({
currencyCode: 'EUR',
locale: language,
value: benefitUnusedAmount,
});
},
},
{ {
header: t('roleLabel'), header: t('roleLabel'),
cell: ({ row }) => { cell: ({ row }) => {
@@ -246,7 +255,7 @@ function useGetColumns(
), ),
}, },
], ],
[t, params, permissions], [t, params, permissions, language],
); );
} }

View File

@@ -2323,6 +2323,7 @@ export type Database = {
Returns: { Returns: {
personal_account_id: string personal_account_id: string
benefit_amount: number benefit_amount: number
benefit_unused_amount: number
} }
} }
get_config: { get_config: {

View File

@@ -196,5 +196,6 @@
"specialCharactersError": "This name cannot contain special characters. Please choose a different one.", "specialCharactersError": "This name cannot contain special characters. Please choose a different one.",
"personalCode": "Personal Code", "personalCode": "Personal Code",
"teamOwnerPersonalCodeLabel": "Owner's Personal Code", "teamOwnerPersonalCodeLabel": "Owner's Personal Code",
"distributedBenefitsAmount": "Assigned benefits" "distributedBenefitsAmount": "Assigned benefits",
"distributedBenefitsUnusedAmount": "Unused benefits"
} }

View File

@@ -196,5 +196,6 @@
"specialCharactersError": "Nimi ei tohi sisaldada erimärke. Palun vali mõni teine.", "specialCharactersError": "Nimi ei tohi sisaldada erimärke. Palun vali mõni teine.",
"personalCode": "Isikukood", "personalCode": "Isikukood",
"teamOwnerPersonalCodeLabel": "Omaniku isikukood", "teamOwnerPersonalCodeLabel": "Omaniku isikukood",
"distributedBenefitsAmount": "Väljastatud toetus" "distributedBenefitsAmount": "Väljastatud toetus",
"distributedBenefitsUnusedAmount": "Jääk"
} }

View File

@@ -196,5 +196,6 @@
"specialCharactersError": "Это имя не может содержать специальные символы. Пожалуйста, выберите другое.", "specialCharactersError": "Это имя не может содержать специальные символы. Пожалуйста, выберите другое.",
"personalCode": "Идентификационный код", "personalCode": "Идентификационный код",
"teamOwnerPersonalCodeLabel": "Идентификационный код владельца", "teamOwnerPersonalCodeLabel": "Идентификационный код владельца",
"distributedBenefitsAmount": "Распределенные выплаты" "distributedBenefitsAmount": "Распределенные выплаты",
"distributedBenefitsUnusedAmount": "Неиспользованные выплаты"
} }

View File

@@ -0,0 +1,30 @@
DROP FUNCTION IF EXISTS medreport.get_benefits_usages_for_company_members(uuid);
CREATE OR REPLACE FUNCTION medreport.get_benefits_usages_for_company_members(p_account_id uuid)
returns table (
personal_account_id uuid,
benefit_amount numeric,
benefit_unused_amount numeric
)
language plpgsql
as $$
begin
return query
with benefit_recipient_accounts as (
-- Find all personal accounts that have received benefits from this company
select distinct account_id
from medreport.account_balance_entries
where source_company_id = p_account_id
and entry_type = 'benefit'
)
select
bra.account_id as personal_account_id,
coalesce(sum(case when abe.entry_type = 'benefit' and abe.source_company_id = p_account_id then abe.amount else 0 end), 0) as benefit_amount,
coalesce(sum(case when abe.entry_type = 'benefit' and abe.source_company_id = p_account_id then abe.amount when abe.entry_type = 'purchase' then abe.amount else 0 end), 0) as benefit_unused_amount
from benefit_recipient_accounts bra
left join medreport.account_balance_entries abe on abe.account_id = bra.account_id
group by bra.account_id;
end;
$$;
grant execute on function medreport.get_benefits_usages_for_company_members(uuid) to authenticated, service_role;

View File

@@ -0,0 +1,48 @@
DROP FUNCTION IF EXISTS medreport.get_account_members(text);
CREATE OR REPLACE FUNCTION medreport.get_account_members(account_slug text)
RETURNS TABLE(
id uuid,
user_id uuid,
account_id uuid,
role character varying,
role_hierarchy_level integer,
primary_owner_user_id uuid,
name text,
email character varying,
personal_code text,
picture_url character varying,
created_at timestamp with time zone,
updated_at timestamp with time zone
)
LANGUAGE plpgsql
SET search_path TO ''
AS $function$begin
return QUERY
select
acc.id,
am.user_id,
am.account_id,
am.account_role,
r.hierarchy_level,
a.primary_owner_user_id,
TRIM(CONCAT(acc.name, ' ', acc.last_name)) as name,
acc.email,
acc.personal_code,
acc.picture_url,
am.created_at,
am.updated_at
from
medreport.accounts_memberships am
join medreport.accounts a on a.id = am.account_id
join medreport.accounts acc on acc.id = am.user_id
join medreport.roles r on r.name = am.account_role
where
a.slug = account_slug;
end;$function$
;
grant
execute on function medreport.get_account_members (text) to authenticated,
service_role;