mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 13:20:31 +00:00
WIP
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import React from 'react';
|
||||
import { useTable, usePagination } from 'react-table'
|
||||
import { useTable, useExpanded, usePagination } from 'react-table'
|
||||
|
||||
export default function DataTable({
|
||||
columns,
|
||||
@@ -32,8 +32,10 @@ export default function DataTable({
|
||||
// This means we'll also have to provide our own
|
||||
// pageCount.
|
||||
// pageCount: controlledPageCount,
|
||||
getSubRows: row => row.children,
|
||||
},
|
||||
usePagination
|
||||
useExpanded,
|
||||
usePagination,
|
||||
);
|
||||
|
||||
return (
|
||||
|
||||
@@ -116,6 +116,10 @@ export default [
|
||||
text: 'Balance Sheet',
|
||||
href: '/dashboard/accounting/balance-sheet',
|
||||
},
|
||||
{
|
||||
text: 'Trial Balance Sheet',
|
||||
href: '/dashboard/accounting/trial-balance-sheet',
|
||||
},
|
||||
{
|
||||
divider: true,
|
||||
},
|
||||
|
||||
@@ -3,10 +3,29 @@ import {
|
||||
fetchGeneralLedger,
|
||||
fetchBalanceSheet,
|
||||
} from 'store/financialStatement/financialStatements.actions';
|
||||
import t from 'store/types';
|
||||
import {
|
||||
getBalanceSheetByQuery,
|
||||
getBalanceSheetColumns,
|
||||
getBalanceSheetIndexByQuery,
|
||||
getBalanceSheetByIndex,
|
||||
getBalanceSheetAssetsAccounts,
|
||||
getBalanceSheetLiabilitiesAccounts,
|
||||
getBalanceSheetQuery,
|
||||
} from 'store/financialStatement/financialStatements.selectors';
|
||||
|
||||
export const mapStateToProps = (state, props) => ({
|
||||
generalLedeger: state.financialStatements.generalLedger,
|
||||
balanceSheets: state.financialStatements.balanceSheets,
|
||||
|
||||
getBalanceSheetByQuery: (query) => getBalanceSheetByQuery(state.financialStatements.balanceSheets, query),
|
||||
getBalanceSheetColumns: (sheetIndex) => getBalanceSheetColumns(state.financialStatements.balanceSheets, sheetIndex),
|
||||
getBalanceSheetIndexByQuery: (query) => getBalanceSheetIndexByQuery(state.financialStatements.balanceSheets, query),
|
||||
getBalanceSheetByIndex: (sheetIndex) => getBalanceSheetByIndex(state.financialStatements.balanceSheets, sheetIndex),
|
||||
|
||||
getBalanceSheetAssetsAccounts: (sheetIndex) => getBalanceSheetAssetsAccounts(state.financialStatements.balanceSheets, sheetIndex),
|
||||
getBalanceSheetLiabilitiesAccounts: (sheetIndex) => getBalanceSheetLiabilitiesAccounts(state.financialStatements.balanceSheets, sheetIndex),
|
||||
|
||||
getBalanceSheetQuery: (sheetIndex) => getBalanceSheetQuery(state.financialStatements.balanceSheets, sheetIndex),
|
||||
});
|
||||
|
||||
export const mapDispatchToProps = (dispatch) => ({
|
||||
|
||||
23
client/src/connectors/ProfitLossSheet.connect.js
Normal file
23
client/src/connectors/ProfitLossSheet.connect.js
Normal file
@@ -0,0 +1,23 @@
|
||||
import {connect} from 'react-redux';
|
||||
import {
|
||||
fetchProfitLossSheet,
|
||||
} from 'store/financialStatement/financialStatements.actions';
|
||||
import {
|
||||
getProfitLossSheetIndex,
|
||||
getProfitLossSheet,
|
||||
getProfitLossSheetColumns,
|
||||
getProfitLossSheetAccounts,
|
||||
} from 'store/financialStatement/financialStatements.selectors';
|
||||
|
||||
export const mapStateToProps = (state, props) => ({
|
||||
getProfitLossSheetIndex: (query) => getProfitLossSheetIndex(state.financialStatements.profitLossSheets, query),
|
||||
getProfitLossSheet: (index) => getProfitLossSheet(state.financialStatements.profitLossSheets, index),
|
||||
getProfitLossSheetColumns: (index) => getProfitLossSheetColumns(state.financialStatements.profitLossSheets, index),
|
||||
getProfitLossSheetAccounts: (index) => getProfitLossSheetAccounts(state.financialStatements.profitLossSheets, index),
|
||||
});
|
||||
|
||||
export const mapDispatchToProps = (dispatch) => ({
|
||||
fetchProfitLossSheet: (query = {}) => dispatch(fetchProfitLossSheet({ query })),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps);
|
||||
21
client/src/connectors/TrialBalanceSheet.connect.js
Normal file
21
client/src/connectors/TrialBalanceSheet.connect.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import {connect} from 'react-redux';
|
||||
import {
|
||||
fetchTrialBalanceSheet
|
||||
} from 'store/financialStatement/financialStatements.actions';
|
||||
import {
|
||||
getTrialBalanceSheetIndex,
|
||||
getTrialBalanceAccounts,
|
||||
getTrialBalanceQuery,
|
||||
} from 'store/financialStatement/financialStatements.selectors';
|
||||
|
||||
export const mapStateToProps = (state, props) => ({
|
||||
getTrialBalanceSheetIndex: (query) => getTrialBalanceSheetIndex(state.financialStatements.trialBalanceSheets, query),
|
||||
getTrialBalanceAccounts: (sheetIndex) => getTrialBalanceAccounts(state.financialStatements.trialBalanceSheets, sheetIndex),
|
||||
getTrialBalanceQuery: (sheetIndex) => getTrialBalanceQuery(state.financialStatements.trialBalanceSheets, sheetIndex),
|
||||
});
|
||||
|
||||
export const mapDispatchToProps = (dispatch) => ({
|
||||
fetchTrialBalanceSheet: (query = {}) => dispatch(fetchTrialBalanceSheet({ query })),
|
||||
});
|
||||
|
||||
export default connect(mapStateToProps, mapDispatchToProps);
|
||||
@@ -1,48 +0,0 @@
|
||||
import React, {useEffect} from 'react';
|
||||
import DashboardConnect from 'connectors/Dashboard.connector';
|
||||
import {compose} from 'utils';
|
||||
import useAsync from 'hooks/async';
|
||||
import FinancialStatementConnect from 'connectors/FinancialStatements.connector';
|
||||
import {useIntl} from 'react-intl';
|
||||
import BalanceSheetHeader from './BalanceSheet/BalanceSheetHeader';
|
||||
import LoadingIndicator from 'components/LoadingIndicator';
|
||||
import BalanceSheetTable from './BalanceSheet/BalanceSheetTable';
|
||||
|
||||
function BalanceSheet({
|
||||
fetchBalanceSheet,
|
||||
changePageTitle,
|
||||
}) {
|
||||
const intl = useIntl();
|
||||
const handleDateChange = () => {};
|
||||
|
||||
const fetchHook = useAsync(async () => {
|
||||
await Promise.all([
|
||||
fetchBalanceSheet({}),
|
||||
]);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
changePageTitle('Balance Sheet');
|
||||
}, []);
|
||||
|
||||
const handleFilterSubmit = (filter) => {
|
||||
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="financial-statement">
|
||||
<BalanceSheetHeader onSubmitFilter={handleFilterSubmit} />
|
||||
|
||||
<div class="financial-statement__body">
|
||||
<LoadingIndicator loading={fetchHook.pending}>
|
||||
<BalanceSheetTable />
|
||||
</LoadingIndicator>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
DashboardConnect,
|
||||
FinancialStatementConnect,
|
||||
)(BalanceSheet);
|
||||
@@ -0,0 +1,86 @@
|
||||
import React, {useEffect, useMemo, 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 {useIntl} from 'react-intl';
|
||||
import BalanceSheetHeader from './BalanceSheetHeader';
|
||||
import LoadingIndicator from 'components/LoadingIndicator';
|
||||
import BalanceSheetTable from './BalanceSheetTable';
|
||||
import moment from 'moment';
|
||||
|
||||
function BalanceSheet({
|
||||
fetchBalanceSheet,
|
||||
changePageTitle,
|
||||
getBalanceSheetByQuery,
|
||||
getBalanceSheetIndexByQuery,
|
||||
getBalanceSheetByIndex,
|
||||
balanceSheets
|
||||
}) {
|
||||
const intl = useIntl();
|
||||
const [filter, setFilter] = useState({
|
||||
from_date: moment().startOf('year').format('YYYY-MM-DD'),
|
||||
to_date: moment().endOf('year').format('YYYY-MM-DD'),
|
||||
basis: 'cash',
|
||||
display_columns_by: 'total',
|
||||
none_zero: false,
|
||||
});
|
||||
|
||||
const [reload, setReload] = useState(false);
|
||||
|
||||
const fetchHook = useAsync(async () => {
|
||||
await Promise.all([
|
||||
fetchBalanceSheet(filter),
|
||||
]);
|
||||
setReload(false);
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
if (!reload) { return; }
|
||||
fetchHook.execute();
|
||||
}, [reload]);
|
||||
|
||||
useEffect(() => {
|
||||
changePageTitle('Balance Sheet');
|
||||
}, []);
|
||||
|
||||
// Retrieve balance sheet index by the given filter query.
|
||||
const balanceSheetIndex = useMemo(() => {
|
||||
return getBalanceSheetIndexByQuery(filter);
|
||||
}, [filter, balanceSheets]);
|
||||
|
||||
// Retreive balance sheet by the given sheet index.
|
||||
const balanceSheet = useMemo(() => {
|
||||
return getBalanceSheetByIndex(balanceSheetIndex);
|
||||
}, [balanceSheetIndex, balanceSheets]);
|
||||
|
||||
// Handle re-fetch balance sheet after filter change.
|
||||
const handleFilterSubmit = (filter) => {
|
||||
setFilter({
|
||||
...filter,
|
||||
from_date: moment(filter.from_date).format('YYYY-MM-DD'),
|
||||
to_date: moment(filter.to_date).format('YYYY-MM-DD'),
|
||||
});
|
||||
setReload(true);
|
||||
};
|
||||
return (
|
||||
<div class="financial-statement">
|
||||
<BalanceSheetHeader
|
||||
pageFilter={filter}
|
||||
onSubmitFilter={handleFilterSubmit} />
|
||||
|
||||
<div class="financial-statement__body">
|
||||
<LoadingIndicator loading={fetchHook.pending}>
|
||||
<BalanceSheetTable
|
||||
balanceSheet={balanceSheet}
|
||||
balanceSheetIndex={balanceSheetIndex} />
|
||||
</LoadingIndicator>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
DashboardConnect,
|
||||
FinancialStatementConnect,
|
||||
)(BalanceSheet);
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, {useState, useMemo} from 'react';
|
||||
import React, {useState, useMemo, useEffect} from 'react';
|
||||
import FinancialStatementHeader from 'containers/Dashboard/FinancialStatements/FinancialStatementHeader';
|
||||
import {Row, Col} from 'react-grid-system';
|
||||
import {
|
||||
@@ -10,44 +10,53 @@ import {
|
||||
Radio,
|
||||
HTMLSelect,
|
||||
Intent,
|
||||
Popover,
|
||||
} from "@blueprintjs/core";
|
||||
import {Select} from '@blueprintjs/select';
|
||||
import {DateInput} from '@blueprintjs/datetime';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {momentFormatter, handleStringChange} from 'utils';
|
||||
import {
|
||||
momentFormatter,
|
||||
handleStringChange,
|
||||
parseDateRangeQuery,
|
||||
} from 'utils';
|
||||
import moment from 'moment';
|
||||
|
||||
export default function BalanceSheetHeader({
|
||||
onSubmitFilter,
|
||||
pageFilter,
|
||||
}) {
|
||||
const intl = useIntl();
|
||||
const [filter, setFilter] = useState({
|
||||
from_date: null,
|
||||
to_date: null,
|
||||
accounting_basis: 'cash',
|
||||
display_columns_by: 'total',
|
||||
});
|
||||
|
||||
const setFilterByName = (name, value) => {
|
||||
setFilter({
|
||||
...filter,
|
||||
[name]: value,
|
||||
});
|
||||
};
|
||||
|
||||
const handleFieldChange = (event) => {
|
||||
setFilterByName(event.target.name, event.target.value);
|
||||
};
|
||||
|
||||
const displayColumnsByOptions = [
|
||||
{key: 'total', name: 'Total'},
|
||||
{key: 'year', name: 'Year'},
|
||||
{key: 'month', name: 'Month'},
|
||||
{key: 'week', name: 'Week'},
|
||||
{key: 'day', name: 'Day'},
|
||||
{key: 'quarter', name: 'Quarter'}
|
||||
{key: 'quarter', name: 'Quarter'},
|
||||
];
|
||||
|
||||
const [filter, setFilter] = useState({
|
||||
...pageFilter,
|
||||
from_date: moment(pageFilter.from_date).toDate(),
|
||||
to_date: moment(pageFilter.to_date).toDate()
|
||||
});
|
||||
|
||||
const setFilterByKey = (name, value) => {
|
||||
setFilter({ ...filter, [name]: value });
|
||||
};
|
||||
|
||||
const [reportDateRange, setReportDateRange] = useState('this_year');
|
||||
|
||||
useEffect(() => {
|
||||
if (reportDateRange === 'custom') { return; }
|
||||
const dateRange = parseDateRangeQuery(reportDateRange);
|
||||
|
||||
if (dateRange) {
|
||||
setFilter((filter) => ({ ...filter, ...dateRange, }));
|
||||
}
|
||||
}, [reportDateRange])
|
||||
|
||||
const selectedDisplayColumnOpt = useMemo(() => {
|
||||
return displayColumnsByOptions.find(o => o.key === filter.display_columns_by);
|
||||
}, [filter.display_columns_by, displayColumnsByOptions]);
|
||||
@@ -56,31 +65,56 @@ export default function BalanceSheetHeader({
|
||||
const accountTypeItem = (item, { handleClick, modifiers, query }) => {
|
||||
return (<MenuItem text={item.name} key={item.id} onClick={handleClick} />);
|
||||
};
|
||||
|
||||
|
||||
// Handle item select of `display columns by` field.
|
||||
const onItemSelectDisplayColumns = (item) => {
|
||||
setFilterByName('display_columns_by', item.key);
|
||||
setFilterByKey('display_columns_by', item.key);
|
||||
};
|
||||
|
||||
// Handle any date change.
|
||||
const handleDateChange = (name) => (date) => {
|
||||
setFilterByName(name, moment(date).format('YYYY-MM-DD'));
|
||||
setReportDateRange('custom');
|
||||
setFilterByKey(name, date);
|
||||
};
|
||||
|
||||
// handle submit filter submit button.
|
||||
const handleSubmitClick = () => {
|
||||
onSubmitFilter(filter);
|
||||
};
|
||||
|
||||
const dateRangeOptions = [
|
||||
{value: 'today', label: 'Today', },
|
||||
{value: 'this_week', label: 'This Week'},
|
||||
{value: 'this_month', label: 'This Month'},
|
||||
{value: 'this_quarter', label: 'This Quarter'},
|
||||
{value: 'this_year', label: 'This Year'},
|
||||
{value: 'custom', label: 'Custom Range'},
|
||||
];
|
||||
|
||||
const [activeRowsColumns, setActiveRowsColumns] = useState(false);
|
||||
|
||||
const onClickActiveRowsColumnsBtn = () => {
|
||||
setActiveRowsColumns(!activeRowsColumns);
|
||||
};
|
||||
|
||||
const activeRowsColumnsPopover = (
|
||||
<div>
|
||||
<h5>Columns</h5>
|
||||
<RadioGroup
|
||||
name="none_zero"
|
||||
selectedValue={filter.none_zero}
|
||||
onChange={handleStringChange((value) => {
|
||||
setFilterByKey('none_zero', value);
|
||||
})}
|
||||
>
|
||||
<Radio label="All" value="0" />
|
||||
<Radio label="Non-Zero" value="1" />
|
||||
</RadioGroup>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<FinancialStatementHeader>
|
||||
<Row>
|
||||
<Col sm={4}>
|
||||
<Col sm={3}>
|
||||
<FormGroup
|
||||
label={intl.formatMessage({'id': 'report_date_range'})}
|
||||
minimal={true}
|
||||
@@ -88,11 +122,13 @@ export default function BalanceSheetHeader({
|
||||
|
||||
<HTMLSelect
|
||||
fill={true}
|
||||
options={dateRangeOptions} />
|
||||
options={dateRangeOptions}
|
||||
value={reportDateRange}
|
||||
onChange={(event) => setReportDateRange(event.target.value)} />
|
||||
</FormGroup>
|
||||
</Col>
|
||||
|
||||
<Col sm={4}>
|
||||
<Col sm={3}>
|
||||
<FormGroup
|
||||
label={intl.formatMessage({'id': 'from_date'})}
|
||||
minimal={true}
|
||||
@@ -100,14 +136,14 @@ export default function BalanceSheetHeader({
|
||||
|
||||
<DateInput
|
||||
{...momentFormatter('YYYY/MM/DD')}
|
||||
defaultValue={new Date()}
|
||||
value={filter.from_date}
|
||||
onChange={handleDateChange('from_date')}
|
||||
popoverProps={{ position: Position.BOTTOM }}
|
||||
fill={true} />
|
||||
</FormGroup>
|
||||
</Col>
|
||||
|
||||
<Col sm={4}>
|
||||
<Col sm={3}>
|
||||
<FormGroup
|
||||
label={intl.formatMessage({'id': 'to_date'})}
|
||||
minimal={true}
|
||||
@@ -115,7 +151,7 @@ export default function BalanceSheetHeader({
|
||||
|
||||
<DateInput
|
||||
{...momentFormatter('YYYY/MM/DD')}
|
||||
defaultValue={new Date()}
|
||||
value={filter.to_date}
|
||||
onChange={handleDateChange('to_date')}
|
||||
popoverProps={{ position: Position.BOTTOM }}
|
||||
fill={true} />
|
||||
@@ -124,11 +160,11 @@ export default function BalanceSheetHeader({
|
||||
</Row>
|
||||
|
||||
<Row>
|
||||
<Col sm={4}>
|
||||
<Col sm={3}>
|
||||
<FormGroup
|
||||
label={'Display report columns'}
|
||||
className="{'form-group-display-columns-by'}"
|
||||
inline={true}>
|
||||
inline={false}>
|
||||
|
||||
<Select
|
||||
items={displayColumnsByOptions}
|
||||
@@ -145,14 +181,34 @@ export default function BalanceSheetHeader({
|
||||
</FormGroup>
|
||||
</Col>
|
||||
|
||||
<Col sm={4}>
|
||||
<Col sm={3}>
|
||||
<FormGroup
|
||||
label={'Show non-zero or active only'}
|
||||
inline={false}>
|
||||
|
||||
<Popover
|
||||
isOpen={activeRowsColumns}
|
||||
content={activeRowsColumnsPopover}
|
||||
minimal={true}
|
||||
position={Position.BOTTOM}>
|
||||
|
||||
<Button
|
||||
rightIcon="caret-down"
|
||||
fill={true}
|
||||
text="Active rows/Columns Active"
|
||||
onClick={onClickActiveRowsColumnsBtn} />
|
||||
</Popover>
|
||||
</FormGroup>
|
||||
</Col>
|
||||
|
||||
<Col sm={3}>
|
||||
<RadioGroup
|
||||
inline={true}
|
||||
label={intl.formatMessage({'id': 'accounting_basis'})}
|
||||
name="accounting_bahandleRadioChangesis"
|
||||
selectedValue={filter.accounting_basis}
|
||||
onChange={handleStringChange((value) => {
|
||||
setFilterByName('accounting_basis', value);
|
||||
setFilterByKey('accounting_basis', value);
|
||||
})}
|
||||
>
|
||||
<Radio label="Cash" value="cash" />
|
||||
@@ -160,10 +216,10 @@ export default function BalanceSheetHeader({
|
||||
</RadioGroup>
|
||||
</Col>
|
||||
|
||||
<Col sm={4}>
|
||||
<Button intent={Intent.PRIMARY} type="submit" onClick={handleSubmitClick}>
|
||||
{ 'Calculate Report' }
|
||||
</Button>
|
||||
<Col sm={3}>
|
||||
<Button intent={Intent.PRIMARY} type="submit" onClick={handleSubmitClick}>
|
||||
{ 'Calculate Report' }
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</FinancialStatementHeader>
|
||||
|
||||
@@ -1,31 +1,114 @@
|
||||
import React, {useMemo, useState} from 'react';
|
||||
import React, {useMemo, useState, 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';
|
||||
|
||||
export default function BalanceSheetTable({
|
||||
function BalanceSheetTable({
|
||||
balanceSheet,
|
||||
balanceSheetIndex,
|
||||
getBalanceSheetColumns,
|
||||
|
||||
getBalanceSheetAssetsAccounts,
|
||||
getBalanceSheetLiabilitiesAccounts,
|
||||
|
||||
getBalanceSheetQuery,
|
||||
}) {
|
||||
const balanceSheetColumns = useMemo(() => {
|
||||
return getBalanceSheetColumns(balanceSheetIndex);
|
||||
}, [getBalanceSheetColumns]);
|
||||
|
||||
const balanceSheetQuery = useMemo(() => {
|
||||
return getBalanceSheetQuery(balanceSheetIndex);
|
||||
}, [getBalanceSheetQuery])
|
||||
|
||||
const columns = useMemo(() => [
|
||||
{
|
||||
// Build our expander column
|
||||
id: 'expander', // Make sure it has an ID
|
||||
Header: ({
|
||||
getToggleAllRowsExpandedProps,
|
||||
isAllRowsExpanded
|
||||
}) => (
|
||||
<span {...getToggleAllRowsExpandedProps()}>
|
||||
{isAllRowsExpanded ? '👇' : '👉'}
|
||||
</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`,
|
||||
},
|
||||
})}
|
||||
>
|
||||
{row.isExpanded ? '👇' : '👉'}
|
||||
</span>
|
||||
) : null,
|
||||
},
|
||||
{
|
||||
Header: 'Account Name',
|
||||
accessor: 'index',
|
||||
accessor: 'name',
|
||||
className: "actions",
|
||||
},
|
||||
{
|
||||
Header: 'Code',
|
||||
accessor: 'note',
|
||||
accessor: 'code',
|
||||
className: "note",
|
||||
},
|
||||
{
|
||||
Header: 'Total',
|
||||
accessor: 'total',
|
||||
className: "credit",
|
||||
},
|
||||
]);
|
||||
|
||||
...(balanceSheetQuery &&
|
||||
balanceSheetQuery.display_columns_by === 'total') ? [
|
||||
{
|
||||
Header: 'Total',
|
||||
accessor: 'balance.formatted_amount',
|
||||
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]);
|
||||
|
||||
const [data, setData] = useState([]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!balanceSheet) { return; }
|
||||
|
||||
setData([
|
||||
{
|
||||
name: 'Assets',
|
||||
code: '',
|
||||
children: [
|
||||
...getBalanceSheetAssetsAccounts(balanceSheetIndex),
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'Liabilies & Equity',
|
||||
code: '',
|
||||
children: [
|
||||
...getBalanceSheetLiabilitiesAccounts(balanceSheetIndex),
|
||||
]
|
||||
}
|
||||
])
|
||||
}, [])
|
||||
|
||||
// if (balanceSheets.length > 0) {
|
||||
// setData(balanceSheets[0].balance_sheet);
|
||||
// }
|
||||
return (
|
||||
<FinancialSheet
|
||||
companyTitle={'Facebook, Incopration'}
|
||||
@@ -38,4 +121,8 @@ export default function BalanceSheetTable({
|
||||
|
||||
</FinancialSheet>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default compose(
|
||||
FinancialStatementConnect,
|
||||
)(BalanceSheetTable);
|
||||
@@ -0,0 +1,78 @@
|
||||
import React, {useState, useEffect, useMemo} from 'react';
|
||||
import ProfitLossSheetHeader from './ProfitLossSheetHeader';
|
||||
import ProfitLossSheetTable from './ProfitLossSheetTable';
|
||||
import LoadingIndicator from 'components/LoadingIndicator';
|
||||
import { useAsync } from 'react-use';
|
||||
import moment from 'moment';
|
||||
import {compose} from 'utils';
|
||||
import DashboardConnect from 'connectors/Dashboard.connector';
|
||||
import ProfitLossSheetConnect from 'connectors/ProfitLossSheet.connect';
|
||||
|
||||
function ProfitLossSheet({
|
||||
changePageTitle,
|
||||
|
||||
fetchProfitLossSheet,
|
||||
|
||||
getProfitLossSheetIndex,
|
||||
getProfitLossSheet,
|
||||
|
||||
getProfitLossSheetAccounts,
|
||||
getProfitLossSheetColumns,
|
||||
}) {
|
||||
const [filter, setFilter] = useState({});
|
||||
const [reload, setReload] = useState(false);
|
||||
|
||||
// Change page title of the dashboard.
|
||||
useEffect(() => {
|
||||
changePageTitle('Trial Balance Sheet');
|
||||
}, []);
|
||||
|
||||
const fetchHook = useAsync(async () => {
|
||||
await Promise.all([
|
||||
fetchProfitLossSheet(filter),
|
||||
]);
|
||||
});
|
||||
|
||||
const handleFilterSubmit = (filter) => {
|
||||
setFilter({
|
||||
...filter,
|
||||
from_date: moment(filter.from_date).format('YYYY-MM-DD'),
|
||||
to_date: moment(filter.to_date).format('YYYY-MM-DD'),
|
||||
});
|
||||
setReload(true);
|
||||
}
|
||||
|
||||
const profitLossSheetIndex = useMemo(() => {
|
||||
return getProfitLossSheetIndex(filter);
|
||||
}, [filter, getProfitLossSheetIndex]);
|
||||
|
||||
const profitLossSheetAccounts = useMemo(() => {
|
||||
return getProfitLossSheetAccounts(profitLossSheetIndex);
|
||||
}, [profitLossSheetIndex, getProfitLossSheet]);
|
||||
|
||||
const profitLossSheetColumns = useMemo(() => {
|
||||
return getProfitLossSheetColumns(profitLossSheetIndex);
|
||||
}, [profitLossSheetIndex])
|
||||
|
||||
return (
|
||||
<div class="financial-statement">
|
||||
<ProfitLossSheetHeader
|
||||
pageFilter={filter}
|
||||
onSubmitFilter={handleFilterSubmit} />
|
||||
|
||||
<div class="financial-statement__body">
|
||||
<LoadingIndicator loading={fetchHook.pending}>
|
||||
|
||||
<ProfitLossSheetTable
|
||||
accounts={profitLossSheetAccounts}
|
||||
columns={profitLossSheetColumns} />
|
||||
</LoadingIndicator>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
export default compose(
|
||||
DashboardConnect,
|
||||
ProfitLossSheetConnect
|
||||
)(ProfitLossSheet);
|
||||
@@ -0,0 +1,227 @@
|
||||
import React, {useState, useMemo, useEffect} from 'react';
|
||||
import FinancialStatementHeader from 'containers/Dashboard/FinancialStatements/FinancialStatementHeader';
|
||||
import {Row, Col} from 'react-grid-system';
|
||||
import {
|
||||
Button,
|
||||
FormGroup,
|
||||
Position,
|
||||
MenuItem,
|
||||
RadioGroup,
|
||||
Radio,
|
||||
HTMLSelect,
|
||||
Intent,
|
||||
Popover,
|
||||
} from "@blueprintjs/core";
|
||||
import {Select} from '@blueprintjs/select';
|
||||
import {DateInput} from '@blueprintjs/datetime';
|
||||
import {useIntl} from 'react-intl';
|
||||
import {
|
||||
momentFormatter,
|
||||
handleStringChange,
|
||||
parseDateRangeQuery,
|
||||
} from 'utils';
|
||||
import moment from 'moment';
|
||||
|
||||
export default function ProfitLossSheetHeader({
|
||||
onSubmitFilter,
|
||||
pageFilter,
|
||||
}) {
|
||||
const intl = useIntl();
|
||||
const displayColumnsByOptions = [
|
||||
{key: 'total', name: 'Total'},
|
||||
{key: 'year', name: 'Year'},
|
||||
{key: 'month', name: 'Month'},
|
||||
{key: 'week', name: 'Week'},
|
||||
{key: 'day', name: 'Day'},
|
||||
{key: 'quarter', name: 'Quarter'},
|
||||
];
|
||||
|
||||
const [filter, setFilter] = useState({
|
||||
...pageFilter,
|
||||
from_date: moment(pageFilter.from_date).toDate(),
|
||||
to_date: moment(pageFilter.to_date).toDate()
|
||||
});
|
||||
|
||||
const setFilterByKey = (name, value) => {
|
||||
setFilter({ ...filter, [name]: value });
|
||||
};
|
||||
|
||||
const [reportDateRange, setReportDateRange] = useState('this_year');
|
||||
|
||||
useEffect(() => {
|
||||
if (reportDateRange === 'custom') { return; }
|
||||
const dateRange = parseDateRangeQuery(reportDateRange);
|
||||
|
||||
if (dateRange) {
|
||||
setFilter((filter) => ({ ...filter, ...dateRange, }));
|
||||
}
|
||||
}, [reportDateRange])
|
||||
|
||||
const selectedDisplayColumnOpt = useMemo(() => {
|
||||
return displayColumnsByOptions.find(o => o.key === filter.display_columns_by);
|
||||
}, [filter.display_columns_by, displayColumnsByOptions]);
|
||||
|
||||
// Account type item of select filed.
|
||||
const accountTypeItem = (item, { handleClick, modifiers, query }) => {
|
||||
return (<MenuItem text={item.name} key={item.id} onClick={handleClick} />);
|
||||
};
|
||||
|
||||
// Handle item select of `display columns by` field.
|
||||
const onItemSelectDisplayColumns = (item) => {
|
||||
setFilterByKey('display_columns_by', item.key);
|
||||
};
|
||||
|
||||
// Handle any date change.
|
||||
const handleDateChange = (name) => (date) => {
|
||||
setReportDateRange('custom');
|
||||
setFilterByKey(name, date);
|
||||
};
|
||||
|
||||
// handle submit filter submit button.
|
||||
const handleSubmitClick = () => {
|
||||
onSubmitFilter(filter);
|
||||
};
|
||||
const dateRangeOptions = [
|
||||
{value: 'today', label: 'Today', },
|
||||
{value: 'this_week', label: 'This Week'},
|
||||
{value: 'this_month', label: 'This Month'},
|
||||
{value: 'this_quarter', label: 'This Quarter'},
|
||||
{value: 'this_year', label: 'This Year'},
|
||||
{value: 'custom', label: 'Custom Range'},
|
||||
];
|
||||
|
||||
const [activeRowsColumns, setActiveRowsColumns] = useState(false);
|
||||
|
||||
const onClickActiveRowsColumnsBtn = () => {
|
||||
setActiveRowsColumns(!activeRowsColumns);
|
||||
};
|
||||
|
||||
const activeRowsColumnsPopover = (
|
||||
<div>
|
||||
<h5>Columns</h5>
|
||||
<RadioGroup
|
||||
name="none_zero"
|
||||
selectedValue={filter.none_zero}
|
||||
onChange={handleStringChange((value) => {
|
||||
setFilterByKey('none_zero', value);
|
||||
})}
|
||||
>
|
||||
<Radio label="All" value="0" />
|
||||
<Radio label="Non-Zero" value="1" />
|
||||
</RadioGroup>
|
||||
</div>
|
||||
);
|
||||
return (
|
||||
<FinancialStatementHeader>
|
||||
<Row>
|
||||
<Col sm={3}>
|
||||
<FormGroup
|
||||
label={intl.formatMessage({'id': 'report_date_range'})}
|
||||
minimal={true}
|
||||
fill={true}>
|
||||
|
||||
<HTMLSelect
|
||||
fill={true}
|
||||
options={dateRangeOptions}
|
||||
value={reportDateRange}
|
||||
onChange={(event) => setReportDateRange(event.target.value)} />
|
||||
</FormGroup>
|
||||
</Col>
|
||||
|
||||
<Col sm={3}>
|
||||
<FormGroup
|
||||
label={intl.formatMessage({'id': 'from_date'})}
|
||||
minimal={true}
|
||||
fill={true}>
|
||||
|
||||
<DateInput
|
||||
{...momentFormatter('YYYY/MM/DD')}
|
||||
value={filter.from_date}
|
||||
onChange={handleDateChange('from_date')}
|
||||
popoverProps={{ position: Position.BOTTOM }}
|
||||
fill={true} />
|
||||
</FormGroup>
|
||||
</Col>
|
||||
|
||||
<Col sm={3}>
|
||||
<FormGroup
|
||||
label={intl.formatMessage({'id': 'to_date'})}
|
||||
minimal={true}
|
||||
fill={true}>
|
||||
|
||||
<DateInput
|
||||
{...momentFormatter('YYYY/MM/DD')}
|
||||
value={filter.to_date}
|
||||
onChange={handleDateChange('to_date')}
|
||||
popoverProps={{ position: Position.BOTTOM }}
|
||||
fill={true} />
|
||||
</FormGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row>
|
||||
<Col sm={3}>
|
||||
<FormGroup
|
||||
label={'Display report columns'}
|
||||
className="{'form-group-display-columns-by'}"
|
||||
inline={false}>
|
||||
|
||||
<Select
|
||||
items={displayColumnsByOptions}
|
||||
noResults={<MenuItem disabled={true} text="No results." />}
|
||||
filterable={false}
|
||||
itemRenderer={accountTypeItem}
|
||||
popoverProps={{ minimal: true }}
|
||||
onItemSelect={onItemSelectDisplayColumns}>
|
||||
<Button
|
||||
rightIcon="caret-down"
|
||||
fill={true}
|
||||
text={selectedDisplayColumnOpt ? selectedDisplayColumnOpt.name : 'Select'} />
|
||||
</Select>
|
||||
</FormGroup>
|
||||
</Col>
|
||||
|
||||
<Col sm={3}>
|
||||
<FormGroup
|
||||
label={'Show non-zero or active only'}
|
||||
inline={false}>
|
||||
|
||||
<Popover
|
||||
isOpen={activeRowsColumns}
|
||||
content={activeRowsColumnsPopover}
|
||||
minimal={true}
|
||||
position={Position.BOTTOM}>
|
||||
|
||||
<Button
|
||||
rightIcon="caret-down"
|
||||
fill={true}
|
||||
text="Active rows/Columns Active"
|
||||
onClick={onClickActiveRowsColumnsBtn} />
|
||||
</Popover>
|
||||
</FormGroup>
|
||||
</Col>
|
||||
|
||||
<Col sm={3}>
|
||||
<RadioGroup
|
||||
inline={true}
|
||||
label={intl.formatMessage({'id': 'accounting_basis'})}
|
||||
name="accounting_bahandleRadioChangesis"
|
||||
selectedValue={filter.accounting_basis}
|
||||
onChange={handleStringChange((value) => {
|
||||
setFilterByKey('accounting_basis', value);
|
||||
})}
|
||||
>
|
||||
<Radio label="Cash" value="cash" />
|
||||
<Radio label="Accural" value="accural" />
|
||||
</RadioGroup>
|
||||
</Col>
|
||||
|
||||
<Col sm={3}>
|
||||
<Button intent={Intent.PRIMARY} type="submit" onClick={handleSubmitClick}>
|
||||
{ 'Calculate Report' }
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</FinancialStatementHeader>
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
import React, { useEffect, useState, useMemo } from 'react';
|
||||
import TrialBalanceSheetHeader from "./TrialBalanceSheetHeader";
|
||||
import LoadingIndicator from 'components/LoadingIndicator';
|
||||
import TrialBalanceSheetTable from './TrialBalanceSheetTable';
|
||||
import { useAsync } from 'react-use';
|
||||
import moment from 'moment';
|
||||
import {compose} from 'utils';
|
||||
import TrialBalanceSheetConnect from 'connectors/TrialBalanceSheet.connect';
|
||||
import DashboardConnect from 'connectors/Dashboard.connector';
|
||||
|
||||
function TrialBalanceSheet({
|
||||
changePageTitle,
|
||||
fetchTrialBalanceSheet,
|
||||
getTrialBalanceSheetIndex,
|
||||
getTrialBalanceAccounts,
|
||||
}) {
|
||||
const [filter, setFilter] = useState({
|
||||
from_date: moment().startOf('year').format('YYYY-MM-DD'),
|
||||
to_date: moment().endOf('year').format('YYYY-MM-DD'),
|
||||
basis: 'cash',
|
||||
none_zero: false,
|
||||
});
|
||||
const [reload, setReload] = useState(false);
|
||||
|
||||
const fetchHook = useAsync(async () => {
|
||||
await Promise.all([
|
||||
fetchTrialBalanceSheet(),
|
||||
]);
|
||||
});
|
||||
|
||||
// Retrieve balance sheet index by the given filter query.
|
||||
const trialBalanceSheetIndex = useMemo(() => {
|
||||
return getTrialBalanceSheetIndex(filter);
|
||||
}, [getTrialBalanceSheetIndex, filter]);
|
||||
|
||||
// Retrieve balance sheet accounts bu the given sheet index.
|
||||
const trialBalanceAccounts = useMemo(() => {
|
||||
return getTrialBalanceAccounts(trialBalanceSheetIndex);
|
||||
}, [trialBalanceSheetIndex]);
|
||||
|
||||
// Change page title of the dashboard.
|
||||
useEffect(() => {
|
||||
changePageTitle('Trial Balance Sheet');
|
||||
}, []);
|
||||
|
||||
const handleFilterSubmit = (filter) => {
|
||||
setFilter({
|
||||
...filter,
|
||||
from_date: moment(filter.from_date).format('YYYY-MM-DD'),
|
||||
to_date: moment(filter.to_date).format('YYYY-MM-DD'),
|
||||
});
|
||||
setReload(true);
|
||||
};
|
||||
|
||||
return (
|
||||
<div class="financial-statement">
|
||||
<TrialBalanceSheetHeader
|
||||
pageFilter={filter}
|
||||
onSubmitFilter={handleFilterSubmit} />
|
||||
|
||||
<div class="financial-statement__body">
|
||||
<LoadingIndicator loading={fetchHook.pending}>
|
||||
<TrialBalanceSheetTable
|
||||
trialBalanceSheetAccounts={trialBalanceAccounts}
|
||||
trialBalanceSheetIndex={trialBalanceSheetIndex} />
|
||||
</LoadingIndicator>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default compose(
|
||||
DashboardConnect,
|
||||
TrialBalanceSheetConnect,
|
||||
)(TrialBalanceSheet);
|
||||
@@ -0,0 +1,113 @@
|
||||
import React, {useState} from 'react';
|
||||
import FinancialStatementHeader from 'containers/Dashboard/FinancialStatements/FinancialStatementHeader';
|
||||
import {Row, Col} from 'react-grid-system';
|
||||
import {
|
||||
Button,
|
||||
FormGroup,
|
||||
Position,
|
||||
MenuItem,
|
||||
RadioGroup,
|
||||
Radio,
|
||||
HTMLSelect,
|
||||
Intent,
|
||||
Popover,
|
||||
} from "@blueprintjs/core";
|
||||
import {DateInput} from '@blueprintjs/datetime';
|
||||
import moment from 'moment';
|
||||
import {momentFormatter} from 'utils';
|
||||
import {useIntl} from 'react-intl';
|
||||
|
||||
export default function TrialBalanceSheetHeader({
|
||||
pageFilter,
|
||||
onSubmitFilter,
|
||||
}) {
|
||||
const intl = useIntl();
|
||||
const [filter, setFilter] = useState({
|
||||
...pageFilter,
|
||||
from_date: moment(pageFilter.from_date).toDate(),
|
||||
to_date: moment(pageFilter.to_date).toDate()
|
||||
})
|
||||
|
||||
const setFilterByKey = (name, value) => {
|
||||
setFilter({ ...filter, [name]: value });
|
||||
};
|
||||
|
||||
const [reportDateRange, setReportDateRange] = useState('this_year');
|
||||
|
||||
const dateRangeOptions = [
|
||||
{value: 'today', label: 'Today', },
|
||||
{value: 'this_week', label: 'This Week'},
|
||||
{value: 'this_month', label: 'This Month'},
|
||||
{value: 'this_quarter', label: 'This Quarter'},
|
||||
{value: 'this_year', label: 'This Year'},
|
||||
{value: 'custom', label: 'Custom Range'},
|
||||
];
|
||||
|
||||
const handleDateChange = (name) => (date) => {
|
||||
setReportDateRange('custom');
|
||||
setFilterByKey(name, date);
|
||||
};
|
||||
|
||||
const handleSubmitClick = () => { onSubmitFilter(filter); };
|
||||
|
||||
return (
|
||||
<FinancialStatementHeader>
|
||||
<Row>
|
||||
<Col sm={3}>
|
||||
<FormGroup
|
||||
label={intl.formatMessage({'id': 'report_date_range'})}
|
||||
minimal={true}
|
||||
fill={true}>
|
||||
|
||||
<HTMLSelect
|
||||
fill={true}
|
||||
options={dateRangeOptions}
|
||||
value={reportDateRange}
|
||||
onChange={(event) => setReportDateRange(event.target.value)} />
|
||||
</FormGroup>
|
||||
</Col>
|
||||
|
||||
<Col sm={3}>
|
||||
<FormGroup
|
||||
label={intl.formatMessage({'id': 'from_date'})}
|
||||
minimal={true}
|
||||
fill={true}>
|
||||
|
||||
<DateInput
|
||||
{...momentFormatter('YYYY/MM/DD')}
|
||||
value={filter.from_date}
|
||||
onChange={handleDateChange('from_date')}
|
||||
popoverProps={{ position: Position.BOTTOM }}
|
||||
fill={true} />
|
||||
</FormGroup>
|
||||
</Col>
|
||||
|
||||
<Col sm={3}>
|
||||
<FormGroup
|
||||
label={intl.formatMessage({'id': 'to_date'})}
|
||||
minimal={true}
|
||||
fill={true}>
|
||||
|
||||
<DateInput
|
||||
{...momentFormatter('YYYY/MM/DD')}
|
||||
value={filter.to_date}
|
||||
onChange={handleDateChange('to_date')}
|
||||
popoverProps={{ position: Position.BOTTOM }}
|
||||
fill={true} />
|
||||
</FormGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Row>
|
||||
<Col sm={3}>
|
||||
<Button
|
||||
intent={Intent.PRIMARY}
|
||||
type="submit"
|
||||
onClick={handleSubmitClick}>
|
||||
{ 'Run Report' }
|
||||
</Button>
|
||||
</Col>
|
||||
</Row>
|
||||
</FinancialStatementHeader>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
import React, {useEffect, useState, useMemo} from 'react';
|
||||
import FinancialSheet from 'components/FinancialSheet';
|
||||
import DataTable from 'components/DataTable';
|
||||
|
||||
|
||||
export default function TrialBalanceSheetTable({
|
||||
trialBalanceSheetAccounts,
|
||||
trialBalanceSheetIndex,
|
||||
}) {
|
||||
const [data, setData] = useState([]);
|
||||
|
||||
const columns = useMemo(() => [
|
||||
{
|
||||
// Build our expander column
|
||||
id: 'expander', // Make sure it has an ID
|
||||
Header: ({
|
||||
getToggleAllRowsExpandedProps,
|
||||
isAllRowsExpanded
|
||||
}) => (
|
||||
<span {...getToggleAllRowsExpandedProps()}>
|
||||
{isAllRowsExpanded ? '👇' : '👉'}
|
||||
</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`,
|
||||
},
|
||||
})}
|
||||
>
|
||||
{row.isExpanded ? '👇' : '👉'}
|
||||
</span>
|
||||
) : null,
|
||||
},
|
||||
{
|
||||
Header: 'Account Name',
|
||||
accessor: 'name',
|
||||
className: "actions",
|
||||
},
|
||||
{
|
||||
Header: 'Code',
|
||||
accessor: 'code',
|
||||
className: "note",
|
||||
},
|
||||
{
|
||||
Header: 'Credit',
|
||||
accessor: 'credit',
|
||||
className: 'credit',
|
||||
},
|
||||
{
|
||||
Header: 'debit',
|
||||
accessor: 'debit',
|
||||
className: 'debit',
|
||||
},
|
||||
{
|
||||
Header: 'Balance',
|
||||
accessor: 'balance',
|
||||
className: 'balance',
|
||||
}
|
||||
], []);
|
||||
|
||||
return (
|
||||
<FinancialSheet
|
||||
companyTitle={'Facebook, Incopration'}
|
||||
sheetType={'Trial Balance Sheet'}
|
||||
date={''}>
|
||||
|
||||
<DataTable
|
||||
columns={columns}
|
||||
data={trialBalanceSheetAccounts} />
|
||||
</FinancialSheet>
|
||||
);
|
||||
}
|
||||
@@ -75,18 +75,25 @@ export default [
|
||||
loader: () => import('containers/Dashboard/FinancialStatements/LedgerSheet')
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: `${BASE_URL}/accounting/trial-balance`,
|
||||
name: 'dashboard.accounting.trial.balance',
|
||||
component: LazyLoader({
|
||||
loader: () => import('containers/Dashboard/FinancialStatements/TrialBalanceSheet')
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: `${BASE_URL}/accounting/balance-sheet`,
|
||||
name: 'dashboard.accounting.balance.sheet',
|
||||
component: LazyLoader({
|
||||
loader: () => import('containers/Dashboard/FinancialStatements/BalanceSheet')
|
||||
loader: () => import('containers/Dashboard/FinancialStatements/BalanceSheet/BalanceSheet')
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: `${BASE_URL}/accounting/trial-balance-sheet`,
|
||||
name: 'dashboard.accounting.trial.balance',
|
||||
component: LazyLoader({
|
||||
loader: () => import('containers/Dashboard/FinancialStatements/TrialBalanceSheet/TrialBalanceSheet')
|
||||
}),
|
||||
},
|
||||
{
|
||||
path: `${BASE_URL}/accounting/profit-loss-sheet`,
|
||||
name: 'dashboard.accounting.profit.loss.sheet',
|
||||
component: LazyLoader({
|
||||
loader: () => import('containers/Dashboard/FinancialStatements/ProfitLossSheet/ProfitLossSheet')
|
||||
}),
|
||||
}
|
||||
];
|
||||
@@ -19,8 +19,33 @@ export const fetchBalanceSheet = ({ query }) => {
|
||||
dispatch({
|
||||
type: t.BALANCE_SHEET_STATEMENT_SET,
|
||||
data: response.data,
|
||||
query: query,
|
||||
});
|
||||
resolve(response);
|
||||
}).catch((error) => { reject(error); });
|
||||
});
|
||||
};
|
||||
|
||||
export const fetchTrialBalanceSheet = ({ query }) => {
|
||||
return (dispatch) => new Promise((resolve, reject) => {
|
||||
ApiService.get('/financial_statements/trial_balance_sheet').then((response) => {
|
||||
dispatch({
|
||||
type: t.TRAIL_BALANCE_STATEMENT_SET,
|
||||
data: response.data,
|
||||
});
|
||||
resolve(response.data);
|
||||
}).catch((error) => { reject(error); })
|
||||
})
|
||||
};
|
||||
|
||||
export const fetchProfitLossSheet = ({ query }) => {
|
||||
return (dispatch) => new Promise((resolve, reject) => {
|
||||
ApiService.get('/financial_statements/profit_loss_sheet').then((response) => {
|
||||
dispatch({
|
||||
type: t.PROFIT_LOSS_STATEMENT_SET,
|
||||
data: response.data,
|
||||
});
|
||||
resolve(response.data);
|
||||
}).catch((error) => { reject(error); });
|
||||
})
|
||||
};
|
||||
@@ -1,14 +1,41 @@
|
||||
import { createReducer } from '@reduxjs/toolkit';
|
||||
import t from 'store/types';
|
||||
import {getBalanceSheetIndexByQuery, getTrialBalanceSheetIndex} from './financialStatements.selectors';
|
||||
import { actionComplete } from '@syncfusion/ej2-react-grids';
|
||||
|
||||
const initialState = {
|
||||
balanceSheet: [],
|
||||
balanceSheets: [],
|
||||
trialBalanceSheets: [],
|
||||
generalLedger: [],
|
||||
trialBalance: [],
|
||||
};
|
||||
|
||||
export default createReducer(initialState, {
|
||||
[t.BALANCE_SHEET_STATEMENT_SET]: (state, action) => {
|
||||
state.balanceSheet.push(action.data);
|
||||
const index = getBalanceSheetIndexByQuery(state.balanceSheets, action.query);
|
||||
|
||||
const balanceSheet = {
|
||||
balances: action.data.balance_sheet,
|
||||
columns: Object.values(action.data.columns),
|
||||
query: action.data.query,
|
||||
};
|
||||
if (index !== -1) {
|
||||
state.balanceSheets[index] = balanceSheet;
|
||||
} else {
|
||||
state.balanceSheets.push(balanceSheet);
|
||||
}
|
||||
},
|
||||
|
||||
[t.TRAIL_BALANCE_STATEMENT_SET]: (state, action) => {
|
||||
const index = getTrialBalanceSheetIndex(state.trialBalanceSheets, action.query);
|
||||
|
||||
const trailBalanceSheet = {
|
||||
accounts: action.data.accounts,
|
||||
query: action.data.query,
|
||||
};
|
||||
if (index !== -1) {
|
||||
state.trialBalanceSheets[index] = trailBalanceSheet;
|
||||
} else {
|
||||
state.trailBalanceSheet.push(trailBalanceSheet);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,91 @@
|
||||
import {getObjectDiff} from 'utils';
|
||||
|
||||
|
||||
// Balance Sheet.
|
||||
export const getBalanceSheetByQuery = (balanceSheets, query) => {
|
||||
return balanceSheets.find(balanceSheet => {
|
||||
return getObjectDiff(query, balanceSheet.query).length === 0;
|
||||
});
|
||||
};
|
||||
|
||||
export const getBalanceSheetIndexByQuery = (balanceSheets, query) => {
|
||||
return balanceSheets.findIndex((balanceSheet) => {
|
||||
return getObjectDiff(query, balanceSheet.query).length === 0;
|
||||
});
|
||||
};
|
||||
|
||||
export const getBalanceSheetByIndex = (balanceSheets, sheetIndex) => {
|
||||
return balanceSheets[sheetIndex];
|
||||
};
|
||||
|
||||
export const getBalanceSheetQuery = (balanceSheets, sheetIndex) => {
|
||||
if (typeof balanceSheets[sheetIndex] === 'object') {
|
||||
return balanceSheets[sheetIndex].query || {};
|
||||
}
|
||||
return {};
|
||||
};
|
||||
|
||||
export const getBalanceSheetAssetsAccounts = (balanceSheets, sheetIndex) => {
|
||||
if (typeof balanceSheets[sheetIndex] === 'object') {
|
||||
return balanceSheets[sheetIndex].balances.assets.accounts || [];
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
export const getBalanceSheetLiabilitiesAccounts = (balanceSheets, sheetIndex) => {
|
||||
if (typeof balanceSheets[sheetIndex] === 'object') {
|
||||
return balanceSheets[sheetIndex].balances.liabilities_equity.accounts || [];
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
export const getBalanceSheetColumns = (balanceSheets, sheetIndex) => {
|
||||
if (typeof balanceSheets[sheetIndex] === 'object') {
|
||||
return balanceSheets[sheetIndex].columns;
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
|
||||
// Trial Balance Sheet.
|
||||
export const getTrialBalanceSheetIndex = (trialBalanceSheets, query) => {
|
||||
return trialBalanceSheets.find((trialBalanceSheet) => {
|
||||
return getObjectDiff(query, trialBalanceSheet.query).length === 0;
|
||||
});
|
||||
};
|
||||
|
||||
export const getTrialBalanceAccounts = (trialBalanceSheets, sheetIndex) => {
|
||||
if (typeof trialBalanceSheets[sheetIndex] === 'object') {
|
||||
return trialBalanceSheets[sheetIndex].accounts;
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
export const getTrialBalanceQuery = (trialBalanceSheets, sheetIndex) => {
|
||||
if (typeof trialBalanceSheets[sheetIndex] === 'object') {
|
||||
return trialBalanceSheets[sheetIndex].query;
|
||||
}
|
||||
return [];
|
||||
};
|
||||
|
||||
// Profit/Loss Sheet selectors.
|
||||
export const getProfitLossSheetIndex = (profitLossSheets, query) => {
|
||||
return profitLossSheets.find((profitLossSheet) => {
|
||||
return getObjectDiff(query, profitLossSheet.query).length === 0;
|
||||
});
|
||||
}
|
||||
|
||||
export const getProfitLossSheet = (profitLossSheets, index) => {
|
||||
return (typeof profitLossSheets[index] !== 'undefined') ?
|
||||
profitLossSheets[index] : null;
|
||||
};
|
||||
|
||||
export const getProfitLossSheetColumns = (profitLossSheets, index) => {
|
||||
const sheet = getProfitLossSheet(profitLossSheets, index);
|
||||
return (sheet) ? sheet.columns : [];
|
||||
};
|
||||
|
||||
export const getProfitLossSheetAccounts = (profitLossSheets, index) => {
|
||||
const sheet = getProfitLossSheet(profitLossSheets, index);
|
||||
return (sheet) ? sheet.accounts : [];
|
||||
};
|
||||
@@ -3,4 +3,5 @@
|
||||
export default {
|
||||
GENERAL_LEDGER_STATEMENT_SET: 'GENERAL_LEDGER_STATEMENT_SET',
|
||||
BALANCE_SHEET_STATEMENT_SET: 'BALANCE_SHEET_STATEMENT_SET',
|
||||
TRAIL_BALANCE_STATEMENT_SET: 'TRAIL_BALANCE_STATEMENT_SET',
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import moment from 'moment';
|
||||
import _ from 'lodash';
|
||||
|
||||
export function removeEmptyFromObject(obj) {
|
||||
obj = Object.assign({}, obj);
|
||||
@@ -76,4 +77,38 @@ export const objectKeysTransform = (obj, transform) => {
|
||||
};
|
||||
|
||||
export const compose = (...funcs) =>
|
||||
funcs.reduce((a, b) => (...args) => a(b(...args)), arg => arg);
|
||||
funcs.reduce((a, b) => (...args) => a(b(...args)), arg => arg);
|
||||
|
||||
export const getObjectDiff = (a, b) => {
|
||||
return _.reduce(a, (result, value, key) => {
|
||||
return _.isEqual(value, b[key]) ?
|
||||
result : result.concat(key);
|
||||
}, []);
|
||||
}
|
||||
|
||||
export const parseDateRangeQuery = (keyword) => {
|
||||
const queries = {
|
||||
'today': {
|
||||
range: 'day',
|
||||
},
|
||||
'this_year': {
|
||||
range: 'year',
|
||||
},
|
||||
'this_month': {
|
||||
range: 'month'
|
||||
},
|
||||
'this_week': {
|
||||
range: 'week'
|
||||
}
|
||||
};
|
||||
|
||||
if (typeof queries[keyword] === 'undefined') {
|
||||
throw new Error(`The date range query ${keyword} is not defined.`);
|
||||
}
|
||||
const query = queries[keyword];
|
||||
|
||||
return {
|
||||
from_date: moment().startOf(query.range).toDate(),
|
||||
to_date: moment().endOf(query.range).toDate(),
|
||||
};
|
||||
};
|
||||
Reference in New Issue
Block a user