diff --git a/pages/api/Schema/index.ts b/pages/api/Schema/index.ts
index 4ccf32fe13..aa8aaffc29 100644
--- a/pages/api/Schema/index.ts
+++ b/pages/api/Schema/index.ts
@@ -39,6 +39,8 @@ import { EntryHistoriesResolvers } from './reports/entryHistories/resolvers';
import ExpectedMonthlyTotalReportTypeDefs from './reports/expectedMonthlyTotal/expectedMonthlyTotal.graphql';
import { ExpectedMonthlyTotalReportResolvers } from './reports/expectedMonthlyTotal/resolvers';
import FinancialAccountsTypeDefs from './reports/financialAccounts/financialAccounts.graphql';
+import FinancialAccountSummaryTypeDefs from './reports/financialAccounts/financialAccounts/financialAccounts.graphql';
+import { FinancialAccountSummaryResolvers } from './reports/financialAccounts/financialAccounts/resolvers';
import { FinancialAccountsResolvers } from './reports/financialAccounts/resolvers';
import FourteenMonthReportTypeDefs from './reports/fourteenMonth/fourteenMonth.graphql';
import { FourteenMonthReportResolvers } from './reports/fourteenMonth/resolvers';
@@ -127,6 +129,10 @@ const schema = buildSubgraphSchema([
typeDefs: DeleteTagsTypeDefs,
resolvers: DeleteTagsResolvers,
},
+ {
+ typeDefs: FinancialAccountSummaryTypeDefs,
+ resolvers: FinancialAccountSummaryResolvers,
+ },
...integrationSchema,
...organizationSchema,
...preferencesSchema,
diff --git a/pages/api/Schema/reports/financialAccounts/financialAccounts/datahandler.ts b/pages/api/Schema/reports/financialAccounts/financialAccounts/datahandler.ts
new file mode 100644
index 0000000000..8aeaa5a242
--- /dev/null
+++ b/pages/api/Schema/reports/financialAccounts/financialAccounts/datahandler.ts
@@ -0,0 +1,38 @@
+import { fetchAllData } from 'src/lib/deserializeJsonApi';
+import { FinancialAccountSummaryResponse } from '../../../../graphql-rest.page.generated';
+
+export interface FinancialAccountSummaryRest {
+ id: string;
+ attributes: {
+ closing_balance: number;
+ credits: number;
+ debits: number;
+ difference: number;
+ end_date: string;
+ opening_balance: number;
+ start_date: string;
+ };
+ relationships: {
+ credit_by_categories: { data: IdType[] };
+ debit_by_categories: { data: IdType[] };
+ };
+}
+
+interface IdType {
+ id: string;
+ type: string;
+}
+
+export const financialAccountSummaryHandler = ({
+ data,
+ included,
+}: {
+ data: FinancialAccountSummaryRest[];
+ included: unknown[];
+}): FinancialAccountSummaryResponse[] => {
+ const financialAccountSummary = data.map((item) => {
+ return fetchAllData(item, included);
+ }) as FinancialAccountSummaryResponse[];
+
+ return financialAccountSummary;
+};
diff --git a/pages/api/Schema/reports/financialAccounts/financialAccounts/financialAccounts.graphql b/pages/api/Schema/reports/financialAccounts/financialAccounts/financialAccounts.graphql
new file mode 100644
index 0000000000..fcff761c40
--- /dev/null
+++ b/pages/api/Schema/reports/financialAccounts/financialAccounts/financialAccounts.graphql
@@ -0,0 +1,35 @@
+extend type Query {
+ financialAccountSummary(
+ input: FinancialAccountSummaryInput!
+ ): [FinancialAccountSummaryResponse]!
+}
+
+input FinancialAccountSummaryInput {
+ accountListId: ID!
+ financialAccountId: ID!
+}
+
+type FinancialAccountSummaryResponse {
+ id: ID!
+ closingBalance: String
+ credits: String
+ debits: String
+ difference: String
+ endDate: String!
+ openingBalance: String
+ startDate: String!
+ creditByCategories: [FinancialAccountSummaryCategory]!
+ debitByCategories: [FinancialAccountSummaryCategory]!
+}
+
+type FinancialAccountSummaryCategory {
+ id: ID!
+ amount: String
+ category: FinancialAccountCategory
+}
+
+type FinancialAccountCategory {
+ id: ID!
+ code: String
+ name: String
+}
diff --git a/pages/api/Schema/reports/financialAccounts/financialAccounts/resolvers.ts b/pages/api/Schema/reports/financialAccounts/financialAccounts/resolvers.ts
new file mode 100644
index 0000000000..dcc43de603
--- /dev/null
+++ b/pages/api/Schema/reports/financialAccounts/financialAccounts/resolvers.ts
@@ -0,0 +1,16 @@
+import { Resolvers } from '../../../../graphql-rest.page.generated';
+
+export const FinancialAccountSummaryResolvers: Resolvers = {
+ Query: {
+ financialAccountSummary: (
+ _source,
+ { input: { accountListId, financialAccountId } },
+ { dataSources },
+ ) => {
+ return dataSources.mpdxRestApi.financialAccountSummary(
+ accountListId,
+ financialAccountId,
+ );
+ },
+ },
+};
diff --git a/pages/api/graphql-rest.page.ts b/pages/api/graphql-rest.page.ts
index 37cc299dc5..ef5803ba4a 100644
--- a/pages/api/graphql-rest.page.ts
+++ b/pages/api/graphql-rest.page.ts
@@ -109,6 +109,7 @@ import {
FinancialAccountResponse,
setActiveFinancialAccount,
} from './Schema/reports/financialAccounts/datahandler';
+import { financialAccountSummaryHandler } from './Schema/reports/financialAccounts/financialAccounts/datahandler';
import {
FourteenMonthReportResponse,
mapFourteenMonthReport,
@@ -758,11 +759,26 @@ class MpdxRestApi extends RESTDataSource {
return setActiveFinancialAccount(data);
}
- async deleteComment(taskId: string, commentId: string) {
- const { data }: { data: DeleteCommentResponse } = await this.delete(
- `tasks/${taskId}/comments/${commentId}`,
+ //
+ // Financial Account Report -- Start
+
+ async financialAccountSummary(
+ accountListId: string,
+ financialAccountId: string,
+ ) {
+ const include =
+ 'credit_by_categories,debit_by_categories,credit_by_categories.category,debit_by_categories.category';
+ const filters = `filter[account_list_id]=${accountListId}&filter[financial_account_id]=${financialAccountId}`;
+ const fields =
+ 'fields[financial_account_entry_by_categories]=amount,category&fields[financial_account_entry_categories]=name,code' +
+ '&fields[reports_entry_histories_periods]=closing_balance,opening_balance,start_date,end_date,credits,debits,difference,credit_by_categories,debit_by_categories';
+
+ const data = await this.get(
+ `reports/entry_histories?${fields}&${filters}&include=${include}`,
);
- return DeleteComment({ ...data, id: commentId });
+
+ return financialAccountSummaryHandler(data);
+ }
}
async getEntryHistories(
@@ -782,6 +798,16 @@ class MpdxRestApi extends RESTDataSource {
});
}
+ //
+ // Financial Account Report -- End
+
+ async deleteComment(taskId: string, commentId: string) {
+ const { data }: { data: DeleteCommentResponse } = await this.delete(
+ `tasks/${taskId}/comments/${commentId}`,
+ );
+ return DeleteComment({ ...data, id: commentId });
+ }
+
async updateComment(taskId: string, commentId: string, body: string) {
const { data }: { data: UpdateCommentResponse } = await this.put(
`tasks/${taskId}/comments/${commentId}`,
diff --git a/src/components/Reports/FinancialAccountsReport/AccountSummary/AccountSummary.test.tsx b/src/components/Reports/FinancialAccountsReport/AccountSummary/AccountSummary.test.tsx
new file mode 100644
index 0000000000..2e94986a03
--- /dev/null
+++ b/src/components/Reports/FinancialAccountsReport/AccountSummary/AccountSummary.test.tsx
@@ -0,0 +1,216 @@
+import React from 'react';
+import { ThemeProvider } from '@mui/material/styles';
+import { AdapterLuxon } from '@mui/x-date-pickers/AdapterLuxon';
+import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
+import { render } from '@testing-library/react';
+import { SnackbarProvider } from 'notistack';
+import { I18nextProvider } from 'react-i18next';
+import TestRouter from '__tests__/util/TestRouter';
+import { GqlMockedProvider } from '__tests__/util/graphqlMocking';
+import { FinancialAccountsWrapper } from 'pages/accountLists/[accountListId]/reports/financialAccounts/Wrapper';
+import i18n from 'src/lib/i18n';
+import theme from 'src/theme';
+import {
+ FinancialAccountContext,
+ FinancialAccountType,
+} from '../Context/FinancialAccountsContext';
+import {
+ AccountSummary,
+ AppendCategoryToCategoriesArray,
+ appendCategoryToCategoriesArray,
+} from './AccountSummary';
+import {
+ creditByCategories,
+ defaultFinancialAccountSummary,
+} from './AccountSummaryMock';
+import { FinancialAccountSummaryQuery } from './financialAccountSummary.generated';
+
+const accountListId = 'accountListId';
+const financialAccountId = 'financialAccountId';
+const router = {
+ query: { accountListId },
+ isReady: true,
+};
+const mutationSpy = jest.fn();
+
+const Component = () => (
+
+
+
+
+
+
+ mocks={{
+ FinancialAccountSummary: defaultFinancialAccountSummary,
+ }}
+ onCall={mutationSpy}
+ >
+
+
+
+
+
+
+
+
+
+
+
+);
+
+describe('AccountSummary', () => {
+ it('regular', async () => {
+ const { getByText, findByText } = render();
+
+ expect(await findByText('Category')).toBeInTheDocument();
+ expect(getByText('Total')).toBeInTheDocument();
+ expect(getByText('Opening Balance')).toBeInTheDocument();
+ expect(getByText('Income')).toBeInTheDocument();
+ expect(getByText('Total Income')).toBeInTheDocument();
+ expect(getByText('Expenses')).toBeInTheDocument();
+ expect(getByText('Total Expenses')).toBeInTheDocument();
+ expect(getByText('Surplus/Deficit')).toBeInTheDocument();
+ expect(getByText('Balance')).toBeInTheDocument();
+ });
+
+ it('should append the categories to the array', async () => {
+ const categoryArray: AppendCategoryToCategoriesArray['categoryArray'] = [];
+ appendCategoryToCategoriesArray({
+ categories:
+ creditByCategories as AppendCategoryToCategoriesArray['categories'],
+ categoryArray,
+ index: 0,
+ });
+
+ expect(categoryArray).toHaveLength(2);
+ expect(categoryArray).toEqual([
+ {
+ id: '111',
+ name: 'Category 1',
+ amounts: [5000],
+ },
+ {
+ id: '222',
+ name: 'Code 2',
+ amounts: [5000],
+ },
+ ]);
+
+ appendCategoryToCategoriesArray({
+ categories: [
+ {
+ ...creditByCategories[0],
+ amount: '-3000',
+ },
+ {
+ ...creditByCategories[1],
+ amount: '-6000',
+ },
+ ] as AppendCategoryToCategoriesArray['categories'],
+ categoryArray,
+ index: 1,
+ });
+
+ expect(categoryArray).toHaveLength(2);
+ expect(categoryArray).toEqual([
+ {
+ id: '111',
+ name: 'Category 1',
+ amounts: [5000, 3000],
+ },
+ {
+ id: '222',
+ name: 'Code 2',
+ amounts: [5000, 6000],
+ },
+ ]);
+ });
+
+ it('should show correct months', async () => {
+ const { getByText, findByText, queryByText } = render();
+
+ expect(await findByText('Jan 24')).toBeInTheDocument();
+ expect(getByText('Feb 24')).toBeInTheDocument();
+ expect(getByText('Mar 24')).toBeInTheDocument();
+ expect(queryByText('Apr 24')).not.toBeInTheDocument();
+ });
+
+ it('should format number to correctly', async () => {
+ const { getByText, findByText } = render();
+ // Turning '-10001.25' into '10,001'
+ expect(await findByText('10,002')).toBeInTheDocument();
+
+ // Turning '5684' to '-5,684'
+ expect(getByText('-5,684')).toBeInTheDocument();
+ });
+
+ it('should show correct data for Opening Balance', async () => {
+ const { getByText, findByText } = render();
+
+ expect(await findByText('Opening Balance')).toBeInTheDocument();
+ expect(getByText('10,002')).toBeInTheDocument();
+ expect(getByText('9,005')).toBeInTheDocument();
+ expect(getByText('12,000')).toBeInTheDocument();
+ expect(getByText('31,000')).toBeInTheDocument();
+ });
+
+ it('should render the categories', async () => {
+ const { getByText, findByText } = render();
+
+ expect(await findByText('Category 1')).toBeInTheDocument();
+ // Should show category code if name is null/undefined
+ expect(getByText('Code 2')).toBeInTheDocument();
+ expect(getByText('Negative Category 1')).toBeInTheDocument();
+ // Should show category code if name is null/undefined
+ expect(getByText('Negative Code 2')).toBeInTheDocument();
+ });
+
+ it('should show correct data for Total Income', async () => {
+ const { getByText, findByText } = render();
+
+ expect(await findByText('Total Income')).toBeInTheDocument();
+ expect(getByText('5,555')).toBeInTheDocument();
+ expect(getByText('6,666')).toBeInTheDocument();
+ expect(getByText('3,333')).toBeInTheDocument();
+ expect(getByText('14,444')).toBeInTheDocument();
+ });
+
+ it('should show correct data for Total Expenses', async () => {
+ const { getByText, findByText } = render();
+
+ expect(await findByText('Total Expenses')).toBeInTheDocument();
+ expect(getByText('2,895')).toBeInTheDocument();
+ expect(getByText('1,689')).toBeInTheDocument();
+ expect(getByText('2,689')).toBeInTheDocument();
+ expect(getByText('5,689')).toBeInTheDocument();
+ });
+
+ it('should show correct data for Surplus/Deficit', async () => {
+ const { getByText, findByText } = render();
+
+ expect(await findByText('Surplus/Deficit')).toBeInTheDocument();
+ expect(getByText('-5,684')).toBeInTheDocument();
+ expect(getByText('-1,864')).toBeInTheDocument();
+ expect(getByText('-3,864')).toBeInTheDocument();
+ expect(getByText('-6,864')).toBeInTheDocument();
+ });
+
+ it('should show correct data for Balance', async () => {
+ const { getByText, findByText } = render();
+
+ expect(await findByText('Balance')).toBeInTheDocument();
+ expect(getByText('7,000')).toBeInTheDocument();
+ expect(getByText('8,000')).toBeInTheDocument();
+ expect(getByText('10,000')).toBeInTheDocument();
+ expect(getByText('25,000')).toBeInTheDocument();
+ });
+});
diff --git a/src/components/Reports/FinancialAccountsReport/AccountSummary/AccountSummary.tsx b/src/components/Reports/FinancialAccountsReport/AccountSummary/AccountSummary.tsx
index 4de130a6fb..e61a7b3974 100644
--- a/src/components/Reports/FinancialAccountsReport/AccountSummary/AccountSummary.tsx
+++ b/src/components/Reports/FinancialAccountsReport/AccountSummary/AccountSummary.tsx
@@ -1,6 +1,384 @@
-import React from 'react';
-import { Box } from '@mui/material';
+import React, { useContext, useMemo } from 'react';
+import {
+ Box,
+ CircularProgress,
+ Divider,
+ Table,
+ TableBody,
+ TableCell,
+ TableContainer,
+ TableHead,
+ TableRow,
+ Typography,
+} from '@mui/material';
+import { styled } from '@mui/material/styles';
+import { DateTime } from 'luxon';
+import { useTranslation } from 'react-i18next';
+import { Maybe } from 'src/graphql/types.generated';
+import { useLocale } from 'src/hooks/useLocale';
+import { monthYearFormat, numberFormat } from 'src/lib/intlFormat';
+import theme from 'src/theme';
+import {
+ FinancialAccountContext,
+ FinancialAccountType,
+} from '../Context/FinancialAccountsContext';
+import { FinancialAccountHeader } from '../Header/Header';
+import {
+ FinancialAccountCategoriesFragment,
+ useFinancialAccountSummaryQuery,
+} from './financialAccountSummary.generated';
+
+const StyledTableCell = styled(TableCell)(({ theme }) => ({
+ padding: `${theme.spacing(1)} ${theme.spacing(2)}`,
+}));
+
+interface Periods {
+ startDateFormatted: string;
+ startDate: string;
+ endDate: string;
+}
+
+interface Category {
+ id: string;
+ name: string;
+ amounts: number[];
+}
+
+export const formatNumber = (
+ numberAsString?: string | number | null,
+ makeAbsolute = true,
+) => {
+ const number =
+ typeof numberAsString === 'string'
+ ? Number(numberAsString)
+ : numberAsString ?? 0;
+ return Math.ceil(makeAbsolute ? Math.abs(number) : number);
+};
+
+export interface AppendCategoryToCategoriesArray {
+ categories: Maybe[];
+ categoryArray: Category[];
+ index: number;
+}
+
+export const appendCategoryToCategoriesArray = ({
+ categories,
+ categoryArray,
+ index,
+}: AppendCategoryToCategoriesArray) => {
+ categories.forEach((category) => {
+ const id = category?.category?.id ?? '';
+ const name = category?.category?.name ?? category?.category?.code ?? '';
+ const amount = formatNumber(category?.amount);
+ if (index === 0) {
+ categoryArray.push({ id, name, amounts: [amount] });
+ } else {
+ const existingCategory = categoryArray.find((c) => c.id === id);
+ if (existingCategory) {
+ existingCategory.amounts.push(amount);
+ }
+ }
+ });
+};
export const AccountSummary: React.FC = () => {
- return AccountSummary;
+ const { t } = useTranslation();
+ const locale = useLocale();
+ const { accountListId, financialAccountId } = useContext(
+ FinancialAccountContext,
+ ) as FinancialAccountType;
+
+ const { data } = useFinancialAccountSummaryQuery({
+ variables: {
+ accountListId,
+ financialAccountId: financialAccountId ?? '',
+ },
+ });
+
+ const tableData = useMemo(() => {
+ const credits: number[] = [];
+ const creditsCategories: Category[] = [];
+ const closingBalances: number[] = [];
+ const debits: number[] = [];
+ const debitsCategories: Category[] = [];
+ const openingBalances: number[] = [];
+ const periods: Periods[] = [];
+ const surplus: number[] = [];
+
+ data?.financialAccountSummary.forEach((item, idx) => {
+ if (!item) {
+ return;
+ }
+
+ // Credits
+ credits.push(formatNumber(item.credits));
+
+ // Closing Balances
+ openingBalances.push(formatNumber(item.openingBalance));
+
+ // Debits
+ debits.push(formatNumber(item.debits));
+
+ // Closing Balances
+ closingBalances.push(formatNumber(item.closingBalance));
+
+ // Surplus
+ /**
+ * If the first character of the `item.difference` is '-', it removes the '-' character.
+ * Otherwise, it prepends the '-' character to the `item.difference` value.
+ */
+ const difference =
+ item.difference?.[0] === '-'
+ ? item.difference.substring(1)
+ : `-${item.difference}`;
+ surplus.push(formatNumber(difference, false));
+
+ // Periods
+ const startDateFormatted = monthYearFormat(
+ DateTime.fromISO(item?.startDate ?? '').month,
+ DateTime.fromISO(item?.startDate ?? '').year,
+ locale,
+ false,
+ );
+ periods.push({
+ startDateFormatted:
+ idx === data.financialAccountSummary.length - 1
+ ? 'Total'
+ : startDateFormatted,
+ startDate: item?.startDate ?? '',
+ endDate: item?.endDate ?? '',
+ });
+
+ // Credits Categories
+ appendCategoryToCategoriesArray({
+ categories: item.creditByCategories,
+ categoryArray: creditsCategories,
+ index: idx,
+ });
+
+ // Debits Categories
+ appendCategoryToCategoriesArray({
+ categories: item.debitByCategories,
+ categoryArray: debitsCategories,
+ index: idx,
+ });
+ });
+
+ return {
+ closingBalances,
+ credits,
+ creditsCategories: creditsCategories.sort((a, b) =>
+ a.name.localeCompare(b.name),
+ ),
+ debits,
+ debitsCategories: debitsCategories.sort((a, b) =>
+ a.name.localeCompare(b.name),
+ ),
+ openingBalances,
+ periods,
+ surplus,
+ };
+ }, [data]);
+
+ return (
+ <>
+
+
+ {!data && (
+
+
+
+ )}
+
+ {data && (
+
+
+
+
+
+
+ {t('Category')}
+
+ {tableData.periods?.map((period, idx) => {
+ return (
+
+ {period.startDateFormatted}
+
+ );
+ })}
+
+
+
+
+ {/* Opening Balance */}
+
+
+
+ {t('Opening Balance')}
+
+
+ {tableData.openingBalances?.map((balance, idx) => {
+ return (
+
+ {numberFormat(balance, locale)}
+
+ );
+ })}
+
+ {/* Income header */}
+
+
+ {t('Income')}
+
+ {tableData.periods?.map((_, idx) => {
+ return (
+
+ );
+ })}
+
+
+ {/* Income Categories */}
+ {tableData.creditsCategories?.map((category, idx) => {
+ return (
+
+
+
+ {category.name}
+
+
+
+ {category.amounts.map((amount, idx) => (
+
+ {numberFormat(amount, locale)}
+
+ ))}
+
+ );
+ })}
+
+ {/* Total Income */}
+
+
+
+ {t('Total Income')}
+
+
+ {tableData.credits?.map((credit, idx) => {
+ return (
+
+
+ {numberFormat(credit, locale)}
+
+
+ );
+ })}
+
+
+ {/* Expenses header */}
+
+
+ {t('Expenses')}
+
+ {tableData.periods?.map((_, idx) => {
+ return (
+
+ );
+ })}
+
+
+ {/* Expenses Categories */}
+ {tableData.debitsCategories?.map((category, idx) => {
+ return (
+
+
+
+ {category.name}
+
+
+
+ {category.amounts.map((amount, idx) => (
+
+ {numberFormat(amount, locale)}
+
+ ))}
+
+ );
+ })}
+
+ {/* Total Expenses */}
+
+
+
+ {t('Total Expenses')}
+
+
+ {tableData.debits?.map((credit, idx) => {
+ return (
+
+
+ {numberFormat(credit, locale)}
+
+
+ );
+ })}
+
+
+ {/* Surplus */}
+
+
+
+ {t('Surplus/Deficit')}
+
+
+ {tableData.surplus?.map((value, idx) => {
+ return (
+
+
+ {numberFormat(value, locale)}
+
+
+ );
+ })}
+
+
+ {/* Closing Balance */}
+
+
+
+ {t('Balance')}
+
+
+ {tableData.closingBalances?.map((balance, idx) => {
+ return (
+
+
+ {numberFormat(balance, locale)}
+
+
+ );
+ })}
+
+
+
+
+
+ )}
+ >
+ );
};
diff --git a/src/components/Reports/FinancialAccountsReport/AccountSummary/AccountSummaryMock.ts b/src/components/Reports/FinancialAccountsReport/AccountSummary/AccountSummaryMock.ts
new file mode 100644
index 0000000000..e47944c033
--- /dev/null
+++ b/src/components/Reports/FinancialAccountsReport/AccountSummary/AccountSummaryMock.ts
@@ -0,0 +1,143 @@
+export const creditByCategories = [
+ {
+ amount: '-5000',
+ category: {
+ id: '111',
+ name: 'Category 1',
+ code: 'Code 1',
+ },
+ },
+ {
+ amount: '-5000',
+ category: {
+ id: '222',
+ name: null,
+ code: 'Code 2',
+ },
+ },
+];
+const debitByCategories = [
+ {
+ amount: '9000',
+ category: {
+ id: '333',
+ name: 'Negative Category 1',
+ code: 'Negative Code 1',
+ },
+ },
+ {
+ amount: '4000',
+ category: {
+ id: '444',
+ name: null,
+ code: 'Negative Code 2',
+ },
+ },
+];
+
+export const defaultFinancialAccountSummary = {
+ financialAccountSummary: [
+ {
+ id: '1',
+ closingBalance: '-7000',
+ credits: '-5555',
+ debits: '2895',
+ difference: '5684',
+ endDate: '2024-01-31',
+ openingBalance: '-10001.25',
+ startDate: '2024-01-01',
+ creditByCategories,
+ debitByCategories,
+ },
+ {
+ id: '2',
+ closingBalance: '-8000',
+ credits: '-6666',
+ debits: '1689',
+ difference: '1864',
+ endDate: '2024-02-29',
+ openingBalance: '-9005',
+ startDate: '2024-02-01',
+ creditByCategories: [
+ {
+ ...creditByCategories[0],
+ amount: '-3000',
+ },
+ {
+ ...creditByCategories[1],
+ amount: '-6000',
+ },
+ ],
+ debitByCategories: [
+ {
+ ...debitByCategories[0],
+ amount: '4000',
+ },
+ {
+ ...debitByCategories[1],
+ amount: '1000',
+ },
+ ],
+ },
+ {
+ id: '3',
+ closingBalance: '-10000',
+ credits: '-3333',
+ debits: '2689',
+ difference: '3864',
+ endDate: '2024-03-31',
+ openingBalance: '-12000',
+ startDate: '2024-03-01',
+ creditByCategories: [
+ {
+ ...creditByCategories[0],
+ amount: '-4500',
+ },
+ {
+ ...creditByCategories[1],
+ amount: '-3000',
+ },
+ ],
+ debitByCategories: [
+ {
+ ...debitByCategories[0],
+ amount: '2000',
+ },
+ {
+ ...debitByCategories[1],
+ amount: '4000',
+ },
+ ],
+ },
+ {
+ id: '4',
+ closingBalance: '-25000',
+ credits: '-14444',
+ debits: '5689',
+ difference: '6864',
+ endDate: '2024-03-31',
+ openingBalance: '-31000',
+ startDate: '2024-01-01',
+ creditByCategories: [
+ {
+ ...creditByCategories[0],
+ amount: '-19000',
+ },
+ {
+ ...creditByCategories[1],
+ amount: '-23000',
+ },
+ ],
+ debitByCategories: [
+ {
+ ...debitByCategories[0],
+ amount: '19500',
+ },
+ {
+ ...debitByCategories[1],
+ amount: '23000',
+ },
+ ],
+ },
+ ],
+};
diff --git a/src/components/Reports/FinancialAccountsReport/AccountSummary/financialAccountSummary.graphql b/src/components/Reports/FinancialAccountsReport/AccountSummary/financialAccountSummary.graphql
new file mode 100644
index 0000000000..643dabb734
--- /dev/null
+++ b/src/components/Reports/FinancialAccountsReport/AccountSummary/financialAccountSummary.graphql
@@ -0,0 +1,33 @@
+query FinancialAccountSummary($accountListId: ID!, $financialAccountId: ID!) {
+ financialAccountSummary(
+ input: {
+ accountListId: $accountListId
+ financialAccountId: $financialAccountId
+ }
+ ) {
+ id
+ closingBalance
+ credits
+ debits
+ difference
+ endDate
+ openingBalance
+ startDate
+ creditByCategories {
+ ...FinancialAccountCategories
+ }
+ debitByCategories {
+ ...FinancialAccountCategories
+ }
+ }
+}
+
+fragment FinancialAccountCategories on FinancialAccountSummaryCategory {
+ id
+ amount
+ category {
+ id
+ code
+ name
+ }
+}
diff --git a/src/lib/intlFormat.ts b/src/lib/intlFormat.ts
index ea9421761d..2c5c7c9194 100644
--- a/src/lib/intlFormat.ts
+++ b/src/lib/intlFormat.ts
@@ -50,10 +50,11 @@ export const monthYearFormat = (
month: number,
year: number,
locale: string,
+ fullYear = true,
): string =>
new Intl.DateTimeFormat(locale, {
month: 'short',
- year: 'numeric',
+ year: fullYear ? 'numeric' : '2-digit',
}).format(DateTime.local(year, month, 1).toJSDate());
export const dateFormat = (date: DateTime | null, locale: string): string => {