WIP Financial statements.

This commit is contained in:
Ahmed Bouhuolia
2020-04-05 14:27:06 +02:00
parent 4227f2f9a8
commit b09fc58042
33 changed files with 725 additions and 343 deletions

View File

@@ -2,7 +2,7 @@ import React, {useEffect, useMemo, useCallback, useState} from 'react';
import DashboardConnect from 'connectors/Dashboard.connector';
import {compose} from 'utils';
import useAsync from 'hooks/async';
import FinancialStatementConnect from 'connectors/FinancialStatements.connector';
import BalanceSheetConnect from 'connectors/BalanceSheet.connect';
import {useIntl} from 'react-intl';
import BalanceSheetHeader from './BalanceSheetHeader';
import LoadingIndicator from 'components/LoadingIndicator';
@@ -15,10 +15,9 @@ import BalanceSheetActionsBar from './BalanceSheetActionsBar';
function BalanceSheet({
fetchBalanceSheet,
changePageTitle,
getBalanceSheetByQuery,
getBalanceSheetIndexByQuery,
getBalanceSheetByIndex,
balanceSheets
balanceSheetLoading,
getBalanceSheetIndex,
getBalanceSheet,
}) {
const intl = useIntl();
const [filter, setFilter] = useState({
@@ -45,13 +44,8 @@ function BalanceSheet({
// Retrieve balance sheet index by the given filter query.
const balanceSheetIndex = useMemo(() =>
getBalanceSheetIndexByQuery(filter),
[filter, getBalanceSheetIndexByQuery]);
// Retreive balance sheet by the given sheet index.
const balanceSheet = useMemo(() =>
getBalanceSheetByIndex(balanceSheetIndex),
[balanceSheetIndex, getBalanceSheetByIndex]);
getBalanceSheetIndex(filter),
[filter, getBalanceSheetIndex]);
// Handle re-fetch balance sheet after filter change.
const handleFilterSubmit = useCallback((filter) => {
@@ -75,13 +69,10 @@ function BalanceSheet({
onSubmitFilter={handleFilterSubmit} />
<div class="financial-statement__body">
<LoadingIndicator loading={fetchHook.pending}>
<BalanceSheetTable
balanceSheet={balanceSheet}
balanceSheetIndex={balanceSheetIndex}
onFetchData={handleFetchData}
asDate={new Date()} />
</LoadingIndicator>
<BalanceSheetTable
loading={balanceSheetLoading}
balanceSheetIndex={balanceSheetIndex}
onFetchData={handleFetchData} />
</div>
</div>
</DashboardPageContent>
@@ -91,5 +82,5 @@ function BalanceSheet({
export default compose(
DashboardConnect,
FinancialStatementConnect,
BalanceSheetConnect,
)(BalanceSheet);

View File

@@ -39,7 +39,7 @@ export default function BalanceSheetHeader({
actions.setSubmitting(false);
},
});
// Handle item select of `display columns by` field.
const onItemSelectDisplayColumns = useCallback((item) => {
formik.setFieldValue('display_columns_type', item.type);
@@ -73,7 +73,8 @@ export default function BalanceSheetHeader({
<Row>
<Col sm={3}>
<SelectDisplayColumnsBy onItemSelect={onItemSelectDisplayColumns} />
<SelectDisplayColumnsBy
onItemSelect={onItemSelectDisplayColumns} />
</Col>
<Col sm={3}>
@@ -102,7 +103,7 @@ export default function BalanceSheetHeader({
type="submit"
onClick={handleSubmitClick}
disabled={formik.isSubmitting}
className={'button--submit-filter'}>
className={'button--submit-filter mt2'}>
{ 'Calculate Report' }
</Button>
</Col>

View File

@@ -1,37 +1,28 @@
import React, {useMemo, useState, useCallback, useEffect} from 'react';
import FinancialSheet from 'components/FinancialSheet';
import DataTable from 'components/DataTable';
import FinancialStatementConnect from 'connectors/FinancialStatements.connector';
import {compose} from 'utils';
import moment from 'moment';
import Money from 'components/Money';
import FinancialSheet from 'components/FinancialSheet';
import DataTable from 'components/DataTable';
import BalanceSheetConnect from 'connectors/BalanceSheet.connect';
import BalanceSheetTableConnect from 'connectors/BalanceSheetTable.connect';
import {
compose,
defaultExpanderReducer,
} from 'utils';
function BalanceSheetTable({
balanceSheet,
balanceSheetIndex,
getBalanceSheetColumns,
getBalanceSheetAssetsAccounts,
getBalanceSheetLiabilitiesAccounts,
getBalanceSheetQuery,
balanceSheetAccounts,
balanceSheetColumns,
balanceSheetQuery,
onFetchData,
asDate,
loading,
}) {
const balanceSheetColumns = useMemo(() =>
getBalanceSheetColumns(balanceSheetIndex),
[getBalanceSheetColumns, balanceSheetIndex]);
const balanceSheetQuery = useMemo(() =>
getBalanceSheetQuery(balanceSheetIndex),
[getBalanceSheetQuery, balanceSheetIndex])
const columns = useMemo(() => [
{
// Build our expander column
id: 'expander', // Make sure it has an ID
className: 'expander',
className: 'expander',
Header: ({
getToggleAllRowsExpandedProps,
isAllRowsExpanded
@@ -77,63 +68,65 @@ function BalanceSheetTable({
accessor: 'code',
className: "code",
},
...(balanceSheetQuery &&
balanceSheetQuery.display_columns_by === 'total') ? [
...(balanceSheetQuery.display_columns_type === 'total') ? [
{
Header: 'Total',
accessor: 'balance.formatted_amount',
Cell: ({ cell }) => {
const row = cell.row.original;
if (!row.balance) { return ''; }
return (<Money amount={row.balance.formatted_amount} currency={'USD'} />);
if (row.total) {
return (<Money amount={row.total.formatted_amount} currency={'USD'} />);
}
return '';
},
className: "credit",
}
] : (balanceSheetColumns.map((column, index) => ({
Header: column,
accessor: (row) => {
if (row.periods_balance && row.periods_balance[index]) {
return row.periods_balance[index].formatted_amount;
}
},
}))),
], [balanceSheetColumns, balanceSheetQuery]);
const [data, setData] = useState([]);
useEffect(() => {
if (!balanceSheet) { return; }
setData([
{
name: 'Assets',
children: getBalanceSheetAssetsAccounts(balanceSheetIndex),
},
{
name: 'Liabilies & Equity',
children: getBalanceSheetLiabilitiesAccounts(balanceSheetIndex),
}
])
}, []);
] : [],
...(balanceSheetQuery.display_columns_type === 'date_periods') ?
(balanceSheetColumns.map((column, index) => ({
id: `date_period_${index}`,
Header: column,
accessor: (row) => {
if (row.total_periods && row.total_periods[index]) {
const amount = row.total_periods[index].formatted_amount;
return (<Money amount={amount} currency={'USD'} />);
}
return '';
},
width: 100,
})))
: [],
], [balanceSheetQuery, balanceSheetColumns]);
const handleFetchData = useCallback(() => {
onFetchData && onFetchData();
}, [onFetchData]);
// Calculates the default expanded rows of balance sheet table.
const expandedRows = useMemo(() =>
defaultExpanderReducer(balanceSheetAccounts, 1),
[balanceSheetAccounts]);
return (
<FinancialSheet
companyTitle={'Facebook, Incopration'}
sheetType={'Balance Sheet'}
date={asDate}>
date={asDate}
loading={loading}>
<DataTable
className="bigcapital-datatable--financial-report"
columns={columns}
data={data}
onFetchData={handleFetchData} />
data={balanceSheetAccounts}
onFetchData={handleFetchData}
expandSubRows={true}
expanded={expandedRows} />
</FinancialSheet>
);
}
export default compose(
FinancialStatementConnect,
BalanceSheetConnect,
BalanceSheetTableConnect,
)(BalanceSheetTable);

View File

@@ -83,7 +83,7 @@ function GeneralLedgerHeader({
type="submit"
onClick={handleSubmitClick}
disabled={formik.isSubmitting}
className={'button--submit-filter'}>
className={'button--submit-filter mt2'}>
{ 'Calculate Report' }
</Button>
</Col>

View File

@@ -3,6 +3,10 @@ import FinancialSheet from 'components/FinancialSheet';
import DataTable from 'components/DataTable';
import Money from 'components/Money';
import moment from 'moment';
import {
defaultExpanderReducer,
} from 'utils';
const ROW_TYPE = {
CLOSING_BALANCE: 'closing_balance',
@@ -135,6 +139,9 @@ export default function GeneralLedgerTable({
onFetchData && onFetchData();
}, [onFetchData]);
// Default expanded rows of general ledger table.
const expandedRows = useMemo(() => defaultExpanderReducer(data, 1), [data]);
return (
<FinancialSheet
companyTitle={'Facebook, Incopration'}
@@ -147,7 +154,11 @@ export default function GeneralLedgerTable({
className="bigcapital-datatable--financial-report"
columns={columns}
data={data}
onFetchData={handleFetchData} />
onFetchData={handleFetchData}
expanded={expandedRows}
virtualizedRows={true}
fixedItemSize={37}
fixedSizeHeight={1000} />
</FinancialSheet>
);
}

View File

@@ -47,7 +47,7 @@ export default function JournalHeader({
<Button
type="submit"
onClick={handleSubmitClick}
class={'button--submit-filter'}>
className={'button--submit-filter'}>
{ 'Run Report' }
</Button>
</Col>

View File

@@ -1,7 +1,7 @@
import React, {useState, useEffect, useCallback, useMemo} from 'react';
import FinancialSheet from 'components/FinancialSheet';
import DataTable from 'components/DataTable';
import {compose} from 'utils';
import {compose, defaultExpanderReducer} from 'utils';
import moment from 'moment';
import JournalConnect from 'connectors/Journal.connect';
import {
@@ -71,6 +71,9 @@ function JournalSheetTable({
onFetchData && onFetchData(...args)
}, [onFetchData]);
// Default expanded rows of general journal table.
const expandedRows = useMemo(() => defaultExpanderReducer(data, 1), [data]);
return (
<FinancialSheet
companyTitle={'Facebook, Incopration'}
@@ -84,7 +87,8 @@ function JournalSheetTable({
columns={columns}
data={data}
onFetchData={handleFetchData}
noResults={"This report does not contain any data."} />
noResults={"This report does not contain any data."}
expanded={expandedRows} />
</FinancialSheet>
);
}

View File

@@ -14,11 +14,11 @@ import moment from 'moment';
function ProfitLossSheet({
changePageTitle,
fetchProfitLossSheet,
getProfitLossSheetIndex,
getProfitLossSheet,
profitLossSheetLoading,
}) {
const [filter, setFilter] = useState({
basis: 'cash',
from_date: moment().startOf('year').format('YYYY-MM-DD'),
to_date: moment().endOf('year').format('YYYY-MM-DD'),
});
@@ -26,7 +26,7 @@ function ProfitLossSheet({
// Change page title of the dashboard.
useEffect(() => {
changePageTitle('Profit/Loss Sheet');
}, []);
}, [changePageTitle]);
// Fetches profit/loss sheet.
const fetchHook = useAsync((query = filter) => {
@@ -35,14 +35,12 @@ function ProfitLossSheet({
]);
}, false);
// Retrieve profit/loss sheet index based on the given filter query.
const profitLossSheetIndex = useMemo(() =>
getProfitLossSheetIndex(filter),
[getProfitLossSheetIndex, filter])
const profitLossSheet = useMemo(() =>
getProfitLossSheet(profitLossSheetIndex),
[getProfitLossSheet, profitLossSheetIndex]);
[getProfitLossSheetIndex, filter]);
// Handle submit filter.
const handleSubmitFilter = useCallback((filter) => {
const _filter = {
...filter,
@@ -51,30 +49,29 @@ function ProfitLossSheet({
};
setFilter(_filter);
fetchHook.execute(_filter);
}, []);
}, [fetchHook]);
// Handle fetch data of profit/loss sheet table.
const handleFetchData = useCallback(() => {
fetchHook.execute();
}, [fetchHook]);
const handleFetchData = useCallback(() => { fetchHook.execute(); }, [fetchHook]);
return (
<DashboardInsider>
<ProfitLossActionsBar />
<DashboardPageContent>
<div class="financial-statement">
<ProfitLossSheetHeader
pageFilter={filter}
onSubmitFilter={handleSubmitFilter} />
<div class="financial-statement">
<ProfitLossSheetHeader
pageFilter={filter}
onSubmitFilter={handleSubmitFilter} />
<div class="financial-statement__body">
<LoadingIndicator loading={false}>
<div class="financial-statement__body">
<ProfitLossSheetTable
data={[]}
onFetchData={handleFetchData} />
</LoadingIndicator>
</div>
</div>
profitLossSheetIndex={profitLossSheetIndex}
onFetchData={handleFetchData}
loading={profitLossSheetLoading} />
</div>
</div>
</DashboardPageContent>
</DashboardInsider>
);
}

View File

@@ -39,7 +39,7 @@ export default function JournalHeader({
const handleItemSelectDisplayColumns = useCallback((item) => {
formik.setFieldValue('display_columns_type', item.type);
formik.setFieldValue('display_columns_by', item.by);
}, []);
}, [formik]);
const handleSubmitClick = useCallback(() => {
formik.submitForm();
@@ -68,7 +68,7 @@ export default function JournalHeader({
<Button
type="submit"
onClick={handleSubmitClick}
className={'button--submit-filter'}>
className={'button--submit-filter mt2'}>
{ 'Run Report' }
</Button>
</Col>

View File

@@ -2,14 +2,59 @@ import React, {useState, useMemo, useCallback} from 'react';
import FinancialSheet from 'components/FinancialSheet';
import DataTable from 'components/DataTable';
import Money from 'components/Money';
import ProfitLossSheetConnect from 'connectors/ProfitLossSheet.connect';
import ProfitLossSheetTableConnect from 'connectors/ProfitLossTable.connect';
import { compose, defaultExpanderReducer } from 'utils';
export default function ProfitLossSheetTable({
function ProfitLossSheetTable({
loading,
data,
onFetchData,
profitLossTableRows,
profitLossQuery,
profitLossColumns
}) {
const columns = useMemo(() => [
{
// Build our expander column
id: 'expander', // Make sure it has an ID
className: 'expander',
Header: ({
getToggleAllRowsExpandedProps,
isAllRowsExpanded
}) => (
<span {...getToggleAllRowsExpandedProps()} className="toggle">
{isAllRowsExpanded ?
(<span class="arrow-down" />) :
(<span class="arrow-right" />)
}
</span>
),
Cell: ({ row }) =>
// Use the row.canExpand and row.getToggleRowExpandedProps prop getter
// to build the toggle for expanding a row
row.canExpand ? (
<span
{...row.getToggleRowExpandedProps({
style: {
// We can even use the row.depth property
// and paddingLeft to indicate the depth
// of the row
paddingLeft: `${row.depth * 2}rem`,
},
className: 'toggle',
})}
>
{row.isExpanded ?
(<span class="arrow-down" />) :
(<span class="arrow-right" />)
}
</span>
) : null,
width: 20,
disableResizing: true,
},
{
Header: 'Account Name',
accessor: 'name',
@@ -20,12 +65,52 @@ export default function ProfitLossSheetTable({
accessor: 'code',
className: "account_code",
},
])
...(profitLossQuery.display_columns_type === 'total') ? [
{
Header: 'Total',
Cell: ({ cell }) => {
const row = cell.row.original;
if (row.total) {
return (<Money amount={row.total.formatted_amount} currency={'USD'} />);
}
return '';
},
className: "total",
}
] : [],
...(profitLossQuery.display_columns_type === 'date_periods') ?
(profitLossColumns.map((column, index) => ({
id: `date_period_${index}`,
Header: column,
accessor: (row) => {
if (row.periods && row.periods[index]) {
const amount = row.periods[index].formatted_amount;
return (<Money amount={amount} currency={'USD'} />);
}
return '';
},
width: 100,
})))
: [],
], [profitLossQuery.display_columns_type, profitLossColumns]);
// Handle data table fetch data.
const handleFetchData = useCallback((...args) => {
onFetchData && onFetchData(...args);
}, [onFetchData]);
// Retrieve default expanded rows of balance sheet.
const expandedRows = useMemo(() =>
defaultExpanderReducer(profitLossTableRows, 1),
[profitLossTableRows]);
// Retrieve conditional datatable row classnames.
const rowClassNames = useCallback((row) => {
return {
[`row--${row.rowType}`]: row.rowType,
};
}, []);
return (
<FinancialSheet
companyTitle={'Facebook, Incopration'}
@@ -37,8 +122,15 @@ export default function ProfitLossSheetTable({
<DataTable
className="bigcapital-datatable--financial-report"
columns={columns}
data={data}
onFetchData={handleFetchData} />
data={profitLossTableRows}
onFetchData={handleFetchData}
expanded={expandedRows}
rowClassNames={rowClassNames} />
</FinancialSheet>
)
}
);
}
export default compose(
ProfitLossSheetConnect,
ProfitLossSheetTableConnect,
)(ProfitLossSheetTable);

View File

@@ -19,6 +19,7 @@ export default function RadiosAccountingBasis(props) {
onChange={handleStringChange((value) => {
onChange && onChange(value);
})}
className={'radio-group---accounting-basis'}
{...rest}>
<Radio label="Cash" value="cash" />
<Radio label="Accural" value="accural" />

View File

@@ -1,6 +1,6 @@
import React, {useMemo, useCallback} from 'react';
import React, { useMemo, useState, useCallback } from 'react';
import SelectList from 'components/SelectList';
import {
FormGroup,
@@ -8,21 +8,31 @@ import {
} from '@blueprintjs/core';
export default function SelectsListColumnsBy(props) {
const { formGroupProps, selectListProps } = props;
const { onItemSelect, formGroupProps, selectListProps } = props;
const [itemSelected, setItemSelected] = useState(null);
const displayColumnsByOptions = useMemo(() => [
{key: 'total', name: 'Total', type: 'total', by: '', },
{key: 'year', name: 'Year', type: 'date', by: 'year'},
{key: 'month', name: 'Month', type: 'date', by: 'month'},
{key: 'week', name: 'Week', type: 'date', by: 'month'},
{key: 'day', name: 'Day', type: 'date', by: 'day'},
{key: 'quarter', name: 'Quarter', type: 'date', by: 'quarter'},
{key: 'year', name: 'Date/Year', type: 'date_periods', by: 'year'},
{key: 'month', name: 'Date/Month', type: 'date_periods', by: 'month'},
{key: 'week', name: 'Date/Week', type: 'date_periods', by: 'month'},
{key: 'day', name: 'Date/Day', type: 'date_periods', by: 'day'},
{key: 'quarter', name: 'Date/Quarter', type: 'date_periods', by: 'quarter'},
]);
const itemRenderer = useCallback((item, { handleClick, modifiers, query }) => {
return (<MenuItem text={item.name} key={item.id} onClick={handleClick} />);
}, []);
const handleItemSelect = useCallback((item) => {
setItemSelected(item);
onItemSelect && onItemSelect(item);
}, [setItemSelected, onItemSelect]);
const buttonLabel = useMemo(() =>
itemSelected ? itemSelected.name : 'Select display columns by...',
[itemSelected]);
return (
<FormGroup
label={'Display report columns'}
@@ -36,7 +46,8 @@ export default function SelectsListColumnsBy(props) {
filterable={false}
itemRenderer={itemRenderer}
popoverProps={{ minimal: true }}
buttonLabel={'Select...'}
buttonLabel={buttonLabel}
onItemSelect={handleItemSelect}
{...selectListProps} />
</FormGroup>
);

View File

@@ -55,7 +55,8 @@ export default function TrialBalanceSheetHeader({
<Button
type="submit"
onClick={handleSubmitClick}
disabled={formik.isSubmitting}>
disabled={formik.isSubmitting}
className={'button--submit-filter'}>
{ 'Run Report' }
</Button>
</Col>