mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-21 07:10:33 +00:00
WIP Financial statements.
This commit is contained in:
@@ -71,6 +71,7 @@
|
|||||||
"react-sortablejs": "^2.0.11",
|
"react-sortablejs": "^2.0.11",
|
||||||
"react-table": "^7.0.0",
|
"react-table": "^7.0.0",
|
||||||
"react-use": "^13.26.1",
|
"react-use": "^13.26.1",
|
||||||
|
"react-window": "^1.8.5",
|
||||||
"redux": "^4.0.5",
|
"redux": "^4.0.5",
|
||||||
"redux-thunk": "^2.3.0",
|
"redux-thunk": "^2.3.0",
|
||||||
"resolve": "1.15.0",
|
"resolve": "1.15.0",
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, {useEffect} from 'react';
|
import React, {useEffect, useMemo, useCallback} from 'react';
|
||||||
import {
|
import {
|
||||||
useTable,
|
useTable,
|
||||||
useExpanded,
|
useExpanded,
|
||||||
@@ -11,6 +11,7 @@ import {
|
|||||||
} from 'react-table'
|
} from 'react-table'
|
||||||
import {Checkbox} from '@blueprintjs/core';
|
import {Checkbox} from '@blueprintjs/core';
|
||||||
import classnames from 'classnames';
|
import classnames from 'classnames';
|
||||||
|
import { FixedSizeList } from 'react-window'
|
||||||
import Icon from 'components/Icon';
|
import Icon from 'components/Icon';
|
||||||
|
|
||||||
const IndeterminateCheckbox = React.forwardRef(
|
const IndeterminateCheckbox = React.forwardRef(
|
||||||
@@ -34,8 +35,15 @@ export default function DataTable({
|
|||||||
onSelectedRowsChange,
|
onSelectedRowsChange,
|
||||||
manualSortBy = 'false',
|
manualSortBy = 'false',
|
||||||
selectionColumn = false,
|
selectionColumn = false,
|
||||||
|
expandSubRows = true,
|
||||||
className,
|
className,
|
||||||
noResults = 'This report does not contain any data.'
|
noResults = 'This report does not contain any data.',
|
||||||
|
expanded = {},
|
||||||
|
rowClassNames,
|
||||||
|
stickyHeader = true,
|
||||||
|
virtualizedRows = false,
|
||||||
|
fixedSizeHeight = 100,
|
||||||
|
fixedItemSize = 30,
|
||||||
}) {
|
}) {
|
||||||
const {
|
const {
|
||||||
getTableProps,
|
getTableProps,
|
||||||
@@ -43,6 +51,7 @@ export default function DataTable({
|
|||||||
headerGroups,
|
headerGroups,
|
||||||
prepareRow,
|
prepareRow,
|
||||||
page,
|
page,
|
||||||
|
rows,
|
||||||
canPreviousPage,
|
canPreviousPage,
|
||||||
canNextPage,
|
canNextPage,
|
||||||
pageOptions,
|
pageOptions,
|
||||||
@@ -52,21 +61,23 @@ export default function DataTable({
|
|||||||
previousPage,
|
previousPage,
|
||||||
setPageSize,
|
setPageSize,
|
||||||
selectedFlatRows,
|
selectedFlatRows,
|
||||||
|
totalColumnsWidth,
|
||||||
|
|
||||||
// Get the state from the instance
|
// Get the state from the instance
|
||||||
state: { pageIndex, pageSize, sortBy, selectedRowIds },
|
state: { pageIndex, pageSize, sortBy, selectedRowIds },
|
||||||
} = useTable(
|
} = useTable(
|
||||||
{
|
{
|
||||||
columns,
|
columns,
|
||||||
data,
|
data: data,
|
||||||
initialState: { pageIndex: 0 }, // Pass our hoisted table state
|
initialState: { pageIndex: 0, expanded }, // Pass our hoisted table state
|
||||||
manualPagination: true, // Tell the usePagination
|
manualPagination: true, // Tell the usePagination
|
||||||
// hook that we'll handle our own data fetching
|
// hook that we'll handle our own data fetching
|
||||||
// This means we'll also have to provide our own
|
// This means we'll also have to provide our own
|
||||||
// pageCount.
|
// pageCount.
|
||||||
// pageCount: controlledPageCount,
|
// pageCount: controlledPageCount,
|
||||||
getSubRows: row => row.children,
|
getSubRows: row => row.children,
|
||||||
manualSortBy
|
manualSortBy,
|
||||||
|
expandSubRows,
|
||||||
},
|
},
|
||||||
useSortBy,
|
useSortBy,
|
||||||
useExpanded,
|
useExpanded,
|
||||||
@@ -108,8 +119,44 @@ export default function DataTable({
|
|||||||
onFetchData && onFetchData({ pageIndex, pageSize, sortBy })
|
onFetchData && onFetchData({ pageIndex, pageSize, sortBy })
|
||||||
}, [pageIndex, pageSize, sortBy]);
|
}, [pageIndex, pageSize, sortBy]);
|
||||||
|
|
||||||
|
// Renders table row.
|
||||||
|
const RenderRow = useCallback(({ style = {}, row }) => {
|
||||||
|
prepareRow(row);
|
||||||
|
return (
|
||||||
|
<div {...row.getRowProps({ style })} className="tr">
|
||||||
|
{row.cells.map((cell) => {
|
||||||
|
return <div {...cell.getCellProps({
|
||||||
|
className: classnames(cell.column.className || '', 'td'),
|
||||||
|
})}>{ cell.render('Cell') }</div>
|
||||||
|
})}
|
||||||
|
</div>);
|
||||||
|
}, [prepareRow]);
|
||||||
|
|
||||||
|
// Renders virtualize circle table rows.
|
||||||
|
const RenderVirtualizedRows = useCallback(({ index, style }) => {
|
||||||
|
const row = rows[index];
|
||||||
|
return RenderRow({ row, style });
|
||||||
|
}, [RenderRow, rows]);
|
||||||
|
|
||||||
|
const RenderPage = useCallback(({ style, index } = {}) => {
|
||||||
|
return page.map((row, index) => RenderRow({ row }));
|
||||||
|
}, [RenderRow, page]);
|
||||||
|
|
||||||
|
const RenderTBody = useCallback(() => {
|
||||||
|
return (virtualizedRows) ? (
|
||||||
|
<FixedSizeList
|
||||||
|
height={fixedSizeHeight}
|
||||||
|
itemCount={rows.length}
|
||||||
|
itemSize={fixedItemSize}
|
||||||
|
>
|
||||||
|
{RenderVirtualizedRows}
|
||||||
|
</FixedSizeList>
|
||||||
|
) : RenderPage();
|
||||||
|
}, [fixedSizeHeight, rows, fixedItemSize, virtualizedRows,
|
||||||
|
RenderVirtualizedRows, RenderPage])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classnames('bigcapital-datatable', className)}>
|
<div className={classnames('bigcapital-datatable', className, {'has-sticky-header': stickyHeader})}>
|
||||||
<div {...getTableProps()} className="table">
|
<div {...getTableProps()} className="table">
|
||||||
<div className="thead">
|
<div className="thead">
|
||||||
{headerGroups.map(headerGroup => (
|
{headerGroups.map(headerGroup => (
|
||||||
@@ -144,18 +191,7 @@ export default function DataTable({
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div {...getTableBodyProps()} className="tbody">
|
<div {...getTableBodyProps()} className="tbody">
|
||||||
{page.map((row, i) => {
|
{ RenderTBody() }
|
||||||
prepareRow(row);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div {...row.getRowProps()} className="tr">
|
|
||||||
{row.cells.map((cell) => {
|
|
||||||
return <div {...cell.getCellProps({
|
|
||||||
className: classnames(cell.column.className || '', 'td'),
|
|
||||||
})}>{ cell.render('Cell') }</div>
|
|
||||||
})}
|
|
||||||
</div>)
|
|
||||||
})}
|
|
||||||
|
|
||||||
{ (page.length === 0) && (
|
{ (page.length === 0) && (
|
||||||
<div className={'tr no-results'}>
|
<div className={'tr no-results'}>
|
||||||
|
|||||||
@@ -11,12 +11,13 @@ export default function FinancialSheet({
|
|||||||
accountingBasis,
|
accountingBasis,
|
||||||
name,
|
name,
|
||||||
loading,
|
loading,
|
||||||
|
className,
|
||||||
}) {
|
}) {
|
||||||
const formattedDate = moment(date).format('DD MMMM YYYY')
|
const formattedDate = moment(date).format('DD MMMM YYYY')
|
||||||
const nameModifer = name ? `financial-sheet--${name}` : '';
|
const nameModifer = name ? `financial-sheet--${name}` : '';
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={classnames('financial-sheet', nameModifer)}>
|
<div className={classnames('financial-sheet', nameModifer, className)}>
|
||||||
<LoadingIndicator loading={loading}>
|
<LoadingIndicator loading={loading}>
|
||||||
<h1 class="financial-sheet__title">{ companyTitle }</h1>
|
<h1 class="financial-sheet__title">{ companyTitle }</h1>
|
||||||
<h6 class="financial-sheet__sheet-type">{ sheetType }</h6>
|
<h6 class="financial-sheet__sheet-type">{ sheetType }</h6>
|
||||||
@@ -29,6 +30,10 @@ export default function FinancialSheet({
|
|||||||
<div class="financial-sheet__accounting-basis">
|
<div class="financial-sheet__accounting-basis">
|
||||||
{ accountingBasis }
|
{ accountingBasis }
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="financial-sheet__basis">
|
||||||
|
Accounting Basis: Accural
|
||||||
|
</div>
|
||||||
</LoadingIndicator>
|
</LoadingIndicator>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
27
client/src/connectors/BalanceSheet.connect.js
Normal file
27
client/src/connectors/BalanceSheet.connect.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import {connect} from 'react-redux';
|
||||||
|
import {
|
||||||
|
fetchBalanceSheet,
|
||||||
|
} from 'store/financialStatement/financialStatements.actions';
|
||||||
|
import {
|
||||||
|
getFinancialSheetIndexByQuery,
|
||||||
|
getFinancialSheet,
|
||||||
|
getFinancialSheetAccounts,
|
||||||
|
getFinancialSheetColumns,
|
||||||
|
getFinancialSheetQuery,
|
||||||
|
} from 'store/financialStatement/financialStatements.selectors';
|
||||||
|
|
||||||
|
|
||||||
|
export const mapStateToProps = (state, props) => ({
|
||||||
|
getBalanceSheetIndex: (query) => getFinancialSheetIndexByQuery(state.financialStatements.balanceSheet.sheets, query),
|
||||||
|
getBalanceSheet: (index) => getFinancialSheet(state.financialStatements.balanceSheet.sheets, index),
|
||||||
|
getBalanceSheetAccounts: (index) => getFinancialSheetAccounts(state.financialStatements.balanceSheet.sheets, index),
|
||||||
|
getBalanceSheetColumns:(index) => getFinancialSheetColumns(state.financialStatements.balanceSheet.sheets, index),
|
||||||
|
getBalanceSheetQuery: (index) => getFinancialSheetQuery(state.financialStatements.balanceSheet.sheets, index),
|
||||||
|
balanceSheetLoading: state.financialStatements.balanceSheet.loading,
|
||||||
|
});
|
||||||
|
|
||||||
|
export const mapDispatchToProps = (dispatch) => ({
|
||||||
|
fetchBalanceSheet: (query = {}) => dispatch(fetchBalanceSheet({ query })),
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps);
|
||||||
27
client/src/connectors/BalanceSheetTable.connect.js
Normal file
27
client/src/connectors/BalanceSheetTable.connect.js
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
import {connect} from 'react-redux';
|
||||||
|
import {
|
||||||
|
fetchBalanceSheet,
|
||||||
|
} from 'store/financialStatement/financialStatements.actions';
|
||||||
|
import {
|
||||||
|
getFinancialSheetIndexByQuery,
|
||||||
|
getFinancialSheet,
|
||||||
|
getFinancialSheetsAccounts,
|
||||||
|
getFinancialSheetsColumns,
|
||||||
|
} from 'store/financialStatement/financialStatements.selectors';
|
||||||
|
|
||||||
|
|
||||||
|
export const mapStateToProps = (state, props) => {
|
||||||
|
const sheetIndex = props.balanceSheetIndex;
|
||||||
|
|
||||||
|
return {
|
||||||
|
balanceSheetAccounts: props.getBalanceSheetAccounts(sheetIndex),
|
||||||
|
balanceSheetQuery: props.getBalanceSheetQuery(sheetIndex),
|
||||||
|
balanceSheetColumns: props.getBalanceSheetColumns(sheetIndex),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mapDispatchToProps = (dispatch) => ({
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps);
|
||||||
@@ -5,11 +5,19 @@ import {
|
|||||||
import {
|
import {
|
||||||
getFinancialSheetIndexByQuery,
|
getFinancialSheetIndexByQuery,
|
||||||
getFinancialSheet,
|
getFinancialSheet,
|
||||||
|
getFinancialSheetColumns,
|
||||||
|
getFinancialSheetQuery,
|
||||||
|
getFinancialSheetTableRows,
|
||||||
} from 'store/financialStatement/financialStatements.selectors';
|
} from 'store/financialStatement/financialStatements.selectors';
|
||||||
|
|
||||||
export const mapStateToProps = (state, props) => ({
|
export const mapStateToProps = (state, props) => ({
|
||||||
getProfitLossSheetIndex: (query) => getFinancialSheetIndexByQuery(state.financialStatements.profitLoss.sheets, query),
|
getProfitLossSheetIndex: (query) => getFinancialSheetIndexByQuery(state.financialStatements.profitLoss.sheets, query),
|
||||||
getProfitLossSheet: (index) => getFinancialSheet(state.financialStatements.profitLoss.sheets, index),
|
getProfitLossSheet: (index) => getFinancialSheet(state.financialStatements.profitLoss.sheets, index),
|
||||||
|
getProfitLossColumns: (index) => getFinancialSheetColumns(state.financialStatements.profitLoss.sheets, index),
|
||||||
|
getProfitLossQuery: (index) => getFinancialSheetQuery(state.financialStatements.profitLoss.sheets, index),
|
||||||
|
getProfitLossTableRows: (index) => getFinancialSheetTableRows(state.financialStatements.profitLoss.sheets, index),
|
||||||
|
|
||||||
|
profitLossSheetLoading: state.financialStatements.profitLoss.loading,
|
||||||
});
|
});
|
||||||
|
|
||||||
export const mapDispatchToProps = (dispatch) => ({
|
export const mapDispatchToProps = (dispatch) => ({
|
||||||
|
|||||||
17
client/src/connectors/ProfitLossTable.connect.js
Normal file
17
client/src/connectors/ProfitLossTable.connect.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import {connect} from 'react-redux';
|
||||||
|
|
||||||
|
export const mapStateToProps = (state, props) => {
|
||||||
|
const sheetIndex = props.profitLossSheetIndex;
|
||||||
|
|
||||||
|
return {
|
||||||
|
profitLossTableRows: props.getProfitLossTableRows(sheetIndex),
|
||||||
|
profitLossColumns: props.getProfitLossColumns(sheetIndex),
|
||||||
|
profitLossQuery: props.getProfitLossQuery(sheetIndex),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export const mapDispatchToProps = (dispatch) => ({
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
export default connect(mapStateToProps, mapDispatchToProps);
|
||||||
@@ -3,16 +3,15 @@ import {
|
|||||||
fetchTrialBalanceSheet
|
fetchTrialBalanceSheet
|
||||||
} from 'store/financialStatement/financialStatements.actions';
|
} from 'store/financialStatement/financialStatements.actions';
|
||||||
import {
|
import {
|
||||||
getTrialBalanceSheetIndex,
|
|
||||||
getTrialBalanceAccounts,
|
|
||||||
getTrialBalanceQuery,
|
|
||||||
getFinancialSheetIndexByQuery,
|
getFinancialSheetIndexByQuery,
|
||||||
|
getFinancialSheetAccounts,
|
||||||
|
getFinancialSheetQuery,
|
||||||
} from 'store/financialStatement/financialStatements.selectors';
|
} from 'store/financialStatement/financialStatements.selectors';
|
||||||
|
|
||||||
export const mapStateToProps = (state, props) => ({
|
export const mapStateToProps = (state, props) => ({
|
||||||
getTrialBalanceSheetIndex: (query) => getFinancialSheetIndexByQuery(state.financialStatements.trialBalance.sheets, query),
|
getTrialBalanceSheetIndex: (query) => getFinancialSheetIndexByQuery(state.financialStatements.trialBalance.sheets, query),
|
||||||
getTrialBalanceAccounts: (sheetIndex) => getTrialBalanceAccounts(state.financialStatements.trialBalance.sheets, sheetIndex),
|
getTrialBalanceAccounts: (sheetIndex) => getFinancialSheetAccounts(state.financialStatements.trialBalance.sheets, sheetIndex),
|
||||||
getTrialBalanceQuery: (sheetIndex) => getTrialBalanceQuery(state.financialStatements.trialBalance.sheets, sheetIndex),
|
getTrialBalanceQuery: (sheetIndex) => getFinancialSheetQuery(state.financialStatements.trialBalance.sheets, sheetIndex),
|
||||||
|
|
||||||
trialBalanceSheetLoading: state.financialStatements.trialBalance.loading,
|
trialBalanceSheetLoading: state.financialStatements.trialBalance.loading,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import React, {useEffect, useMemo, useCallback, useState} from 'react';
|
|||||||
import DashboardConnect from 'connectors/Dashboard.connector';
|
import DashboardConnect from 'connectors/Dashboard.connector';
|
||||||
import {compose} from 'utils';
|
import {compose} from 'utils';
|
||||||
import useAsync from 'hooks/async';
|
import useAsync from 'hooks/async';
|
||||||
import FinancialStatementConnect from 'connectors/FinancialStatements.connector';
|
import BalanceSheetConnect from 'connectors/BalanceSheet.connect';
|
||||||
import {useIntl} from 'react-intl';
|
import {useIntl} from 'react-intl';
|
||||||
import BalanceSheetHeader from './BalanceSheetHeader';
|
import BalanceSheetHeader from './BalanceSheetHeader';
|
||||||
import LoadingIndicator from 'components/LoadingIndicator';
|
import LoadingIndicator from 'components/LoadingIndicator';
|
||||||
@@ -15,10 +15,9 @@ import BalanceSheetActionsBar from './BalanceSheetActionsBar';
|
|||||||
function BalanceSheet({
|
function BalanceSheet({
|
||||||
fetchBalanceSheet,
|
fetchBalanceSheet,
|
||||||
changePageTitle,
|
changePageTitle,
|
||||||
getBalanceSheetByQuery,
|
balanceSheetLoading,
|
||||||
getBalanceSheetIndexByQuery,
|
getBalanceSheetIndex,
|
||||||
getBalanceSheetByIndex,
|
getBalanceSheet,
|
||||||
balanceSheets
|
|
||||||
}) {
|
}) {
|
||||||
const intl = useIntl();
|
const intl = useIntl();
|
||||||
const [filter, setFilter] = useState({
|
const [filter, setFilter] = useState({
|
||||||
@@ -45,13 +44,8 @@ function BalanceSheet({
|
|||||||
|
|
||||||
// Retrieve balance sheet index by the given filter query.
|
// Retrieve balance sheet index by the given filter query.
|
||||||
const balanceSheetIndex = useMemo(() =>
|
const balanceSheetIndex = useMemo(() =>
|
||||||
getBalanceSheetIndexByQuery(filter),
|
getBalanceSheetIndex(filter),
|
||||||
[filter, getBalanceSheetIndexByQuery]);
|
[filter, getBalanceSheetIndex]);
|
||||||
|
|
||||||
// Retreive balance sheet by the given sheet index.
|
|
||||||
const balanceSheet = useMemo(() =>
|
|
||||||
getBalanceSheetByIndex(balanceSheetIndex),
|
|
||||||
[balanceSheetIndex, getBalanceSheetByIndex]);
|
|
||||||
|
|
||||||
// Handle re-fetch balance sheet after filter change.
|
// Handle re-fetch balance sheet after filter change.
|
||||||
const handleFilterSubmit = useCallback((filter) => {
|
const handleFilterSubmit = useCallback((filter) => {
|
||||||
@@ -75,13 +69,10 @@ function BalanceSheet({
|
|||||||
onSubmitFilter={handleFilterSubmit} />
|
onSubmitFilter={handleFilterSubmit} />
|
||||||
|
|
||||||
<div class="financial-statement__body">
|
<div class="financial-statement__body">
|
||||||
<LoadingIndicator loading={fetchHook.pending}>
|
<BalanceSheetTable
|
||||||
<BalanceSheetTable
|
loading={balanceSheetLoading}
|
||||||
balanceSheet={balanceSheet}
|
balanceSheetIndex={balanceSheetIndex}
|
||||||
balanceSheetIndex={balanceSheetIndex}
|
onFetchData={handleFetchData} />
|
||||||
onFetchData={handleFetchData}
|
|
||||||
asDate={new Date()} />
|
|
||||||
</LoadingIndicator>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</DashboardPageContent>
|
</DashboardPageContent>
|
||||||
@@ -91,5 +82,5 @@ function BalanceSheet({
|
|||||||
|
|
||||||
export default compose(
|
export default compose(
|
||||||
DashboardConnect,
|
DashboardConnect,
|
||||||
FinancialStatementConnect,
|
BalanceSheetConnect,
|
||||||
)(BalanceSheet);
|
)(BalanceSheet);
|
||||||
@@ -73,7 +73,8 @@ export default function BalanceSheetHeader({
|
|||||||
|
|
||||||
<Row>
|
<Row>
|
||||||
<Col sm={3}>
|
<Col sm={3}>
|
||||||
<SelectDisplayColumnsBy onItemSelect={onItemSelectDisplayColumns} />
|
<SelectDisplayColumnsBy
|
||||||
|
onItemSelect={onItemSelectDisplayColumns} />
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
<Col sm={3}>
|
<Col sm={3}>
|
||||||
@@ -102,7 +103,7 @@ export default function BalanceSheetHeader({
|
|||||||
type="submit"
|
type="submit"
|
||||||
onClick={handleSubmitClick}
|
onClick={handleSubmitClick}
|
||||||
disabled={formik.isSubmitting}
|
disabled={formik.isSubmitting}
|
||||||
className={'button--submit-filter'}>
|
className={'button--submit-filter mt2'}>
|
||||||
{ 'Calculate Report' }
|
{ 'Calculate Report' }
|
||||||
</Button>
|
</Button>
|
||||||
</Col>
|
</Col>
|
||||||
|
|||||||
@@ -1,32 +1,23 @@
|
|||||||
import React, {useMemo, useState, useCallback, useEffect} from 'react';
|
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 moment from 'moment';
|
||||||
import Money from 'components/Money';
|
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({
|
function BalanceSheetTable({
|
||||||
balanceSheet,
|
balanceSheetAccounts,
|
||||||
balanceSheetIndex,
|
balanceSheetColumns,
|
||||||
getBalanceSheetColumns,
|
balanceSheetQuery,
|
||||||
|
|
||||||
getBalanceSheetAssetsAccounts,
|
|
||||||
getBalanceSheetLiabilitiesAccounts,
|
|
||||||
|
|
||||||
getBalanceSheetQuery,
|
|
||||||
|
|
||||||
onFetchData,
|
onFetchData,
|
||||||
asDate,
|
asDate,
|
||||||
|
loading,
|
||||||
}) {
|
}) {
|
||||||
const balanceSheetColumns = useMemo(() =>
|
|
||||||
getBalanceSheetColumns(balanceSheetIndex),
|
|
||||||
[getBalanceSheetColumns, balanceSheetIndex]);
|
|
||||||
|
|
||||||
const balanceSheetQuery = useMemo(() =>
|
|
||||||
getBalanceSheetQuery(balanceSheetIndex),
|
|
||||||
[getBalanceSheetQuery, balanceSheetIndex])
|
|
||||||
|
|
||||||
const columns = useMemo(() => [
|
const columns = useMemo(() => [
|
||||||
{
|
{
|
||||||
// Build our expander column
|
// Build our expander column
|
||||||
@@ -77,63 +68,65 @@ function BalanceSheetTable({
|
|||||||
accessor: 'code',
|
accessor: 'code',
|
||||||
className: "code",
|
className: "code",
|
||||||
},
|
},
|
||||||
...(balanceSheetQuery &&
|
...(balanceSheetQuery.display_columns_type === 'total') ? [
|
||||||
balanceSheetQuery.display_columns_by === 'total') ? [
|
|
||||||
{
|
{
|
||||||
Header: 'Total',
|
Header: 'Total',
|
||||||
accessor: 'balance.formatted_amount',
|
accessor: 'balance.formatted_amount',
|
||||||
Cell: ({ cell }) => {
|
Cell: ({ cell }) => {
|
||||||
const row = cell.row.original;
|
const row = cell.row.original;
|
||||||
if (!row.balance) { return ''; }
|
if (row.total) {
|
||||||
return (<Money amount={row.balance.formatted_amount} currency={'USD'} />);
|
return (<Money amount={row.total.formatted_amount} currency={'USD'} />);
|
||||||
|
}
|
||||||
|
return '';
|
||||||
},
|
},
|
||||||
className: "credit",
|
className: "credit",
|
||||||
}
|
}
|
||||||
] : (balanceSheetColumns.map((column, index) => ({
|
] : [],
|
||||||
Header: column,
|
...(balanceSheetQuery.display_columns_type === 'date_periods') ?
|
||||||
accessor: (row) => {
|
(balanceSheetColumns.map((column, index) => ({
|
||||||
if (row.periods_balance && row.periods_balance[index]) {
|
id: `date_period_${index}`,
|
||||||
return row.periods_balance[index].formatted_amount;
|
Header: column,
|
||||||
}
|
accessor: (row) => {
|
||||||
},
|
if (row.total_periods && row.total_periods[index]) {
|
||||||
}))),
|
const amount = row.total_periods[index].formatted_amount;
|
||||||
], [balanceSheetColumns, balanceSheetQuery]);
|
return (<Money amount={amount} currency={'USD'} />);
|
||||||
|
}
|
||||||
const [data, setData] = useState([]);
|
return '';
|
||||||
|
},
|
||||||
useEffect(() => {
|
width: 100,
|
||||||
if (!balanceSheet) { return; }
|
})))
|
||||||
setData([
|
: [],
|
||||||
{
|
], [balanceSheetQuery, balanceSheetColumns]);
|
||||||
name: 'Assets',
|
|
||||||
children: getBalanceSheetAssetsAccounts(balanceSheetIndex),
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: 'Liabilies & Equity',
|
|
||||||
children: getBalanceSheetLiabilitiesAccounts(balanceSheetIndex),
|
|
||||||
}
|
|
||||||
])
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const handleFetchData = useCallback(() => {
|
const handleFetchData = useCallback(() => {
|
||||||
onFetchData && onFetchData();
|
onFetchData && onFetchData();
|
||||||
}, [onFetchData]);
|
}, [onFetchData]);
|
||||||
|
|
||||||
|
|
||||||
|
// Calculates the default expanded rows of balance sheet table.
|
||||||
|
const expandedRows = useMemo(() =>
|
||||||
|
defaultExpanderReducer(balanceSheetAccounts, 1),
|
||||||
|
[balanceSheetAccounts]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FinancialSheet
|
<FinancialSheet
|
||||||
companyTitle={'Facebook, Incopration'}
|
companyTitle={'Facebook, Incopration'}
|
||||||
sheetType={'Balance Sheet'}
|
sheetType={'Balance Sheet'}
|
||||||
date={asDate}>
|
date={asDate}
|
||||||
|
loading={loading}>
|
||||||
|
|
||||||
<DataTable
|
<DataTable
|
||||||
className="bigcapital-datatable--financial-report"
|
className="bigcapital-datatable--financial-report"
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={data}
|
data={balanceSheetAccounts}
|
||||||
onFetchData={handleFetchData} />
|
onFetchData={handleFetchData}
|
||||||
|
expandSubRows={true}
|
||||||
|
expanded={expandedRows} />
|
||||||
</FinancialSheet>
|
</FinancialSheet>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default compose(
|
export default compose(
|
||||||
FinancialStatementConnect,
|
BalanceSheetConnect,
|
||||||
|
BalanceSheetTableConnect,
|
||||||
)(BalanceSheetTable);
|
)(BalanceSheetTable);
|
||||||
@@ -83,7 +83,7 @@ function GeneralLedgerHeader({
|
|||||||
type="submit"
|
type="submit"
|
||||||
onClick={handleSubmitClick}
|
onClick={handleSubmitClick}
|
||||||
disabled={formik.isSubmitting}
|
disabled={formik.isSubmitting}
|
||||||
className={'button--submit-filter'}>
|
className={'button--submit-filter mt2'}>
|
||||||
{ 'Calculate Report' }
|
{ 'Calculate Report' }
|
||||||
</Button>
|
</Button>
|
||||||
</Col>
|
</Col>
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ import FinancialSheet from 'components/FinancialSheet';
|
|||||||
import DataTable from 'components/DataTable';
|
import DataTable from 'components/DataTable';
|
||||||
import Money from 'components/Money';
|
import Money from 'components/Money';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import {
|
||||||
|
defaultExpanderReducer,
|
||||||
|
} from 'utils';
|
||||||
|
|
||||||
|
|
||||||
const ROW_TYPE = {
|
const ROW_TYPE = {
|
||||||
CLOSING_BALANCE: 'closing_balance',
|
CLOSING_BALANCE: 'closing_balance',
|
||||||
@@ -135,6 +139,9 @@ export default function GeneralLedgerTable({
|
|||||||
onFetchData && onFetchData();
|
onFetchData && onFetchData();
|
||||||
}, [onFetchData]);
|
}, [onFetchData]);
|
||||||
|
|
||||||
|
// Default expanded rows of general ledger table.
|
||||||
|
const expandedRows = useMemo(() => defaultExpanderReducer(data, 1), [data]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FinancialSheet
|
<FinancialSheet
|
||||||
companyTitle={'Facebook, Incopration'}
|
companyTitle={'Facebook, Incopration'}
|
||||||
@@ -147,7 +154,11 @@ export default function GeneralLedgerTable({
|
|||||||
className="bigcapital-datatable--financial-report"
|
className="bigcapital-datatable--financial-report"
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={data}
|
data={data}
|
||||||
onFetchData={handleFetchData} />
|
onFetchData={handleFetchData}
|
||||||
|
expanded={expandedRows}
|
||||||
|
virtualizedRows={true}
|
||||||
|
fixedItemSize={37}
|
||||||
|
fixedSizeHeight={1000} />
|
||||||
</FinancialSheet>
|
</FinancialSheet>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -47,7 +47,7 @@ export default function JournalHeader({
|
|||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
onClick={handleSubmitClick}
|
onClick={handleSubmitClick}
|
||||||
class={'button--submit-filter'}>
|
className={'button--submit-filter'}>
|
||||||
{ 'Run Report' }
|
{ 'Run Report' }
|
||||||
</Button>
|
</Button>
|
||||||
</Col>
|
</Col>
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React, {useState, useEffect, useCallback, useMemo} from 'react';
|
import React, {useState, useEffect, useCallback, useMemo} from 'react';
|
||||||
import FinancialSheet from 'components/FinancialSheet';
|
import FinancialSheet from 'components/FinancialSheet';
|
||||||
import DataTable from 'components/DataTable';
|
import DataTable from 'components/DataTable';
|
||||||
import {compose} from 'utils';
|
import {compose, defaultExpanderReducer} from 'utils';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import JournalConnect from 'connectors/Journal.connect';
|
import JournalConnect from 'connectors/Journal.connect';
|
||||||
import {
|
import {
|
||||||
@@ -71,6 +71,9 @@ function JournalSheetTable({
|
|||||||
onFetchData && onFetchData(...args)
|
onFetchData && onFetchData(...args)
|
||||||
}, [onFetchData]);
|
}, [onFetchData]);
|
||||||
|
|
||||||
|
// Default expanded rows of general journal table.
|
||||||
|
const expandedRows = useMemo(() => defaultExpanderReducer(data, 1), [data]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FinancialSheet
|
<FinancialSheet
|
||||||
companyTitle={'Facebook, Incopration'}
|
companyTitle={'Facebook, Incopration'}
|
||||||
@@ -84,7 +87,8 @@ function JournalSheetTable({
|
|||||||
columns={columns}
|
columns={columns}
|
||||||
data={data}
|
data={data}
|
||||||
onFetchData={handleFetchData}
|
onFetchData={handleFetchData}
|
||||||
noResults={"This report does not contain any data."} />
|
noResults={"This report does not contain any data."}
|
||||||
|
expanded={expandedRows} />
|
||||||
</FinancialSheet>
|
</FinancialSheet>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ import moment from 'moment';
|
|||||||
function ProfitLossSheet({
|
function ProfitLossSheet({
|
||||||
changePageTitle,
|
changePageTitle,
|
||||||
fetchProfitLossSheet,
|
fetchProfitLossSheet,
|
||||||
|
|
||||||
getProfitLossSheetIndex,
|
getProfitLossSheetIndex,
|
||||||
getProfitLossSheet,
|
profitLossSheetLoading,
|
||||||
}) {
|
}) {
|
||||||
const [filter, setFilter] = useState({
|
const [filter, setFilter] = useState({
|
||||||
|
basis: 'cash',
|
||||||
from_date: moment().startOf('year').format('YYYY-MM-DD'),
|
from_date: moment().startOf('year').format('YYYY-MM-DD'),
|
||||||
to_date: moment().endOf('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.
|
// Change page title of the dashboard.
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
changePageTitle('Profit/Loss Sheet');
|
changePageTitle('Profit/Loss Sheet');
|
||||||
}, []);
|
}, [changePageTitle]);
|
||||||
|
|
||||||
// Fetches profit/loss sheet.
|
// Fetches profit/loss sheet.
|
||||||
const fetchHook = useAsync((query = filter) => {
|
const fetchHook = useAsync((query = filter) => {
|
||||||
@@ -35,14 +35,12 @@ function ProfitLossSheet({
|
|||||||
]);
|
]);
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
|
// Retrieve profit/loss sheet index based on the given filter query.
|
||||||
const profitLossSheetIndex = useMemo(() =>
|
const profitLossSheetIndex = useMemo(() =>
|
||||||
getProfitLossSheetIndex(filter),
|
getProfitLossSheetIndex(filter),
|
||||||
[getProfitLossSheetIndex, filter])
|
[getProfitLossSheetIndex, filter]);
|
||||||
|
|
||||||
const profitLossSheet = useMemo(() =>
|
|
||||||
getProfitLossSheet(profitLossSheetIndex),
|
|
||||||
[getProfitLossSheet, profitLossSheetIndex]);
|
|
||||||
|
|
||||||
|
// Handle submit filter.
|
||||||
const handleSubmitFilter = useCallback((filter) => {
|
const handleSubmitFilter = useCallback((filter) => {
|
||||||
const _filter = {
|
const _filter = {
|
||||||
...filter,
|
...filter,
|
||||||
@@ -51,30 +49,29 @@ function ProfitLossSheet({
|
|||||||
};
|
};
|
||||||
setFilter(_filter);
|
setFilter(_filter);
|
||||||
fetchHook.execute(_filter);
|
fetchHook.execute(_filter);
|
||||||
}, []);
|
}, [fetchHook]);
|
||||||
|
|
||||||
// Handle fetch data of profit/loss sheet table.
|
// Handle fetch data of profit/loss sheet table.
|
||||||
const handleFetchData = useCallback(() => {
|
const handleFetchData = useCallback(() => { fetchHook.execute(); }, [fetchHook]);
|
||||||
fetchHook.execute();
|
|
||||||
}, [fetchHook]);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DashboardInsider>
|
<DashboardInsider>
|
||||||
<ProfitLossActionsBar />
|
<ProfitLossActionsBar />
|
||||||
|
|
||||||
<div class="financial-statement">
|
<DashboardPageContent>
|
||||||
<ProfitLossSheetHeader
|
<div class="financial-statement">
|
||||||
pageFilter={filter}
|
<ProfitLossSheetHeader
|
||||||
onSubmitFilter={handleSubmitFilter} />
|
pageFilter={filter}
|
||||||
|
onSubmitFilter={handleSubmitFilter} />
|
||||||
|
|
||||||
<div class="financial-statement__body">
|
<div class="financial-statement__body">
|
||||||
<LoadingIndicator loading={false}>
|
|
||||||
<ProfitLossSheetTable
|
<ProfitLossSheetTable
|
||||||
data={[]}
|
profitLossSheetIndex={profitLossSheetIndex}
|
||||||
onFetchData={handleFetchData} />
|
onFetchData={handleFetchData}
|
||||||
</LoadingIndicator>
|
loading={profitLossSheetLoading} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</DashboardPageContent>
|
||||||
</DashboardInsider>
|
</DashboardInsider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ export default function JournalHeader({
|
|||||||
const handleItemSelectDisplayColumns = useCallback((item) => {
|
const handleItemSelectDisplayColumns = useCallback((item) => {
|
||||||
formik.setFieldValue('display_columns_type', item.type);
|
formik.setFieldValue('display_columns_type', item.type);
|
||||||
formik.setFieldValue('display_columns_by', item.by);
|
formik.setFieldValue('display_columns_by', item.by);
|
||||||
}, []);
|
}, [formik]);
|
||||||
|
|
||||||
const handleSubmitClick = useCallback(() => {
|
const handleSubmitClick = useCallback(() => {
|
||||||
formik.submitForm();
|
formik.submitForm();
|
||||||
@@ -68,7 +68,7 @@ export default function JournalHeader({
|
|||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
onClick={handleSubmitClick}
|
onClick={handleSubmitClick}
|
||||||
className={'button--submit-filter'}>
|
className={'button--submit-filter mt2'}>
|
||||||
{ 'Run Report' }
|
{ 'Run Report' }
|
||||||
</Button>
|
</Button>
|
||||||
</Col>
|
</Col>
|
||||||
|
|||||||
@@ -2,14 +2,59 @@ import React, {useState, useMemo, useCallback} from 'react';
|
|||||||
import FinancialSheet from 'components/FinancialSheet';
|
import FinancialSheet from 'components/FinancialSheet';
|
||||||
import DataTable from 'components/DataTable';
|
import DataTable from 'components/DataTable';
|
||||||
import Money from 'components/Money';
|
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,
|
loading,
|
||||||
data,
|
data,
|
||||||
onFetchData,
|
onFetchData,
|
||||||
|
profitLossTableRows,
|
||||||
|
profitLossQuery,
|
||||||
|
profitLossColumns
|
||||||
}) {
|
}) {
|
||||||
const columns = useMemo(() => [
|
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',
|
Header: 'Account Name',
|
||||||
accessor: 'name',
|
accessor: 'name',
|
||||||
@@ -20,12 +65,52 @@ export default function ProfitLossSheetTable({
|
|||||||
accessor: 'code',
|
accessor: 'code',
|
||||||
className: "account_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) => {
|
const handleFetchData = useCallback((...args) => {
|
||||||
onFetchData && onFetchData(...args);
|
onFetchData && onFetchData(...args);
|
||||||
}, [onFetchData]);
|
}, [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 (
|
return (
|
||||||
<FinancialSheet
|
<FinancialSheet
|
||||||
companyTitle={'Facebook, Incopration'}
|
companyTitle={'Facebook, Incopration'}
|
||||||
@@ -37,8 +122,15 @@ export default function ProfitLossSheetTable({
|
|||||||
<DataTable
|
<DataTable
|
||||||
className="bigcapital-datatable--financial-report"
|
className="bigcapital-datatable--financial-report"
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={data}
|
data={profitLossTableRows}
|
||||||
onFetchData={handleFetchData} />
|
onFetchData={handleFetchData}
|
||||||
|
expanded={expandedRows}
|
||||||
|
rowClassNames={rowClassNames} />
|
||||||
</FinancialSheet>
|
</FinancialSheet>
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
ProfitLossSheetConnect,
|
||||||
|
ProfitLossSheetTableConnect,
|
||||||
|
)(ProfitLossSheetTable);
|
||||||
@@ -19,6 +19,7 @@ export default function RadiosAccountingBasis(props) {
|
|||||||
onChange={handleStringChange((value) => {
|
onChange={handleStringChange((value) => {
|
||||||
onChange && onChange(value);
|
onChange && onChange(value);
|
||||||
})}
|
})}
|
||||||
|
className={'radio-group---accounting-basis'}
|
||||||
{...rest}>
|
{...rest}>
|
||||||
<Radio label="Cash" value="cash" />
|
<Radio label="Cash" value="cash" />
|
||||||
<Radio label="Accural" value="accural" />
|
<Radio label="Accural" value="accural" />
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
|
|
||||||
import React, {useMemo, useCallback} from 'react';
|
import React, { useMemo, useState, useCallback } from 'react';
|
||||||
import SelectList from 'components/SelectList';
|
import SelectList from 'components/SelectList';
|
||||||
import {
|
import {
|
||||||
FormGroup,
|
FormGroup,
|
||||||
@@ -8,21 +8,31 @@ import {
|
|||||||
} from '@blueprintjs/core';
|
} from '@blueprintjs/core';
|
||||||
|
|
||||||
export default function SelectsListColumnsBy(props) {
|
export default function SelectsListColumnsBy(props) {
|
||||||
const { formGroupProps, selectListProps } = props;
|
const { onItemSelect, formGroupProps, selectListProps } = props;
|
||||||
|
const [itemSelected, setItemSelected] = useState(null);
|
||||||
|
|
||||||
const displayColumnsByOptions = useMemo(() => [
|
const displayColumnsByOptions = useMemo(() => [
|
||||||
{key: 'total', name: 'Total', type: 'total', by: '', },
|
{key: 'total', name: 'Total', type: 'total', by: '', },
|
||||||
{key: 'year', name: 'Year', type: 'date', by: 'year'},
|
{key: 'year', name: 'Date/Year', type: 'date_periods', by: 'year'},
|
||||||
{key: 'month', name: 'Month', type: 'date', by: 'month'},
|
{key: 'month', name: 'Date/Month', type: 'date_periods', by: 'month'},
|
||||||
{key: 'week', name: 'Week', type: 'date', by: 'month'},
|
{key: 'week', name: 'Date/Week', type: 'date_periods', by: 'month'},
|
||||||
{key: 'day', name: 'Day', type: 'date', by: 'day'},
|
{key: 'day', name: 'Date/Day', type: 'date_periods', by: 'day'},
|
||||||
{key: 'quarter', name: 'Quarter', type: 'date', by: 'quarter'},
|
{key: 'quarter', name: 'Date/Quarter', type: 'date_periods', by: 'quarter'},
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const itemRenderer = useCallback((item, { handleClick, modifiers, query }) => {
|
const itemRenderer = useCallback((item, { handleClick, modifiers, query }) => {
|
||||||
return (<MenuItem text={item.name} key={item.id} onClick={handleClick} />);
|
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 (
|
return (
|
||||||
<FormGroup
|
<FormGroup
|
||||||
label={'Display report columns'}
|
label={'Display report columns'}
|
||||||
@@ -36,7 +46,8 @@ export default function SelectsListColumnsBy(props) {
|
|||||||
filterable={false}
|
filterable={false}
|
||||||
itemRenderer={itemRenderer}
|
itemRenderer={itemRenderer}
|
||||||
popoverProps={{ minimal: true }}
|
popoverProps={{ minimal: true }}
|
||||||
buttonLabel={'Select...'}
|
buttonLabel={buttonLabel}
|
||||||
|
onItemSelect={handleItemSelect}
|
||||||
{...selectListProps} />
|
{...selectListProps} />
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ export default function TrialBalanceSheetHeader({
|
|||||||
<Button
|
<Button
|
||||||
type="submit"
|
type="submit"
|
||||||
onClick={handleSubmitClick}
|
onClick={handleSubmitClick}
|
||||||
disabled={formik.isSubmitting}>
|
disabled={formik.isSubmitting}
|
||||||
|
className={'button--submit-filter'}>
|
||||||
{ 'Run Report' }
|
{ 'Run Report' }
|
||||||
</Button>
|
</Button>
|
||||||
</Col>
|
</Col>
|
||||||
|
|||||||
@@ -3,11 +3,19 @@ import t from 'store/types';
|
|||||||
|
|
||||||
export const fetchGeneralLedger = ({ query }) => {
|
export const fetchGeneralLedger = ({ query }) => {
|
||||||
return (dispatch) => new Promise((resolve, reject) => {
|
return (dispatch) => new Promise((resolve, reject) => {
|
||||||
|
dispatch({
|
||||||
|
type: t.GENERAL_LEDGER_SHEET_LOADING,
|
||||||
|
loading: true,
|
||||||
|
})
|
||||||
ApiService.get('/financial_statements/general_ledger', { params: query }).then((response) => {
|
ApiService.get('/financial_statements/general_ledger', { params: query }).then((response) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: t.GENERAL_LEDGER_STATEMENT_SET,
|
type: t.GENERAL_LEDGER_STATEMENT_SET,
|
||||||
data: response.data,
|
data: response.data,
|
||||||
});
|
});
|
||||||
|
dispatch({
|
||||||
|
type: t.GENERAL_LEDGER_SHEET_LOADING,
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
resolve(response);
|
resolve(response);
|
||||||
}).catch((error) => { reject(error); });
|
}).catch((error) => { reject(error); });
|
||||||
});
|
});
|
||||||
@@ -15,12 +23,20 @@ export const fetchGeneralLedger = ({ query }) => {
|
|||||||
|
|
||||||
export const fetchBalanceSheet = ({ query }) => {
|
export const fetchBalanceSheet = ({ query }) => {
|
||||||
return (dispatch) => new Promise((resolve, reject) => {
|
return (dispatch) => new Promise((resolve, reject) => {
|
||||||
|
dispatch({
|
||||||
|
type: t.BALANCE_SHEET_LOADING,
|
||||||
|
loading: true,
|
||||||
|
});
|
||||||
ApiService.get('/financial_statements/balance_sheet', { params: query }).then((response) => {
|
ApiService.get('/financial_statements/balance_sheet', { params: query }).then((response) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: t.BALANCE_SHEET_STATEMENT_SET,
|
type: t.BALANCE_SHEET_STATEMENT_SET,
|
||||||
data: response.data,
|
data: response.data,
|
||||||
query: query,
|
query: query,
|
||||||
});
|
});
|
||||||
|
dispatch({
|
||||||
|
type: t.BALANCE_SHEET_LOADING,
|
||||||
|
loading: false,
|
||||||
|
});
|
||||||
resolve(response);
|
resolve(response);
|
||||||
}).catch((error) => { reject(error); });
|
}).catch((error) => { reject(error); });
|
||||||
});
|
});
|
||||||
@@ -50,9 +66,9 @@ export const fetchProfitLossSheet = ({ query }) => {
|
|||||||
return (dispatch) => new Promise((resolve, reject) => {
|
return (dispatch) => new Promise((resolve, reject) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: t.PROFIT_LOSS_SHEET_LOADING,
|
type: t.PROFIT_LOSS_SHEET_LOADING,
|
||||||
loading: false,
|
loading: true,
|
||||||
});
|
});
|
||||||
ApiService.get('/financial_statements/profit_loss_sheet').then((response) => {
|
ApiService.get('/financial_statements/profit_loss_sheet', { params: query }).then((response) => {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: t.PROFIT_LOSS_SHEET_SET,
|
type: t.PROFIT_LOSS_SHEET_SET,
|
||||||
profitLoss: response.data.profitLoss,
|
profitLoss: response.data.profitLoss,
|
||||||
|
|||||||
@@ -1,14 +1,17 @@
|
|||||||
import { createReducer } from '@reduxjs/toolkit';
|
import { createReducer } from '@reduxjs/toolkit';
|
||||||
import t from 'store/types';
|
import t from 'store/types';
|
||||||
import {
|
import {
|
||||||
getBalanceSheetIndexByQuery,
|
// getBalanceSheetIndexByQuery,
|
||||||
getFinancialSheetIndexByQuery,
|
getFinancialSheetIndexByQuery,
|
||||||
// getFinancialSheetIndexByQuery,
|
// getFinancialSheetIndexByQuery,
|
||||||
} from './financialStatements.selectors';
|
} from './financialStatements.selectors';
|
||||||
import {omit} from 'lodash';
|
import {omit} from 'lodash';
|
||||||
|
|
||||||
const initialState = {
|
const initialState = {
|
||||||
balanceSheets: [],
|
balanceSheet: {
|
||||||
|
sheets: [],
|
||||||
|
loading: false,
|
||||||
|
},
|
||||||
trialBalance: {
|
trialBalance: {
|
||||||
sheets: [],
|
sheets: [],
|
||||||
loading: false,
|
loading: false,
|
||||||
@@ -72,22 +75,61 @@ const mapJournalTableRows = (journal) => {
|
|||||||
}, []);
|
}, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const mapProfitLossToTableRows = (profitLoss) => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
name: 'Income',
|
||||||
|
total: profitLoss.income.total,
|
||||||
|
children: [
|
||||||
|
...profitLoss.income.accounts,
|
||||||
|
{
|
||||||
|
name: 'Total Income',
|
||||||
|
total: profitLoss.income.total,
|
||||||
|
rowType: 'income_total',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Expenses',
|
||||||
|
total: profitLoss.expenses.total,
|
||||||
|
children: [
|
||||||
|
...profitLoss.expenses.accounts,
|
||||||
|
{
|
||||||
|
name: 'Total Expenses',
|
||||||
|
total: profitLoss.expenses.total,
|
||||||
|
rowType: 'expense_total',
|
||||||
|
}
|
||||||
|
],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Net Income',
|
||||||
|
total: profitLoss.net_income.total,
|
||||||
|
rowType: 'net_income',
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
export default createReducer(initialState, {
|
export default createReducer(initialState, {
|
||||||
[t.BALANCE_SHEET_STATEMENT_SET]: (state, action) => {
|
[t.BALANCE_SHEET_STATEMENT_SET]: (state, action) => {
|
||||||
const index = getBalanceSheetIndexByQuery(state.balanceSheets, action.query);
|
const index = getFinancialSheetIndexByQuery(state.balanceSheet.sheets, action.query);
|
||||||
|
|
||||||
const balanceSheet = {
|
const balanceSheet = {
|
||||||
balances: action.data.balance_sheet,
|
accounts: action.data.accounts,
|
||||||
columns: Object.values(action.data.columns),
|
columns: Object.values(action.data.columns),
|
||||||
query: action.data.query,
|
query: action.data.query,
|
||||||
};
|
};
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
state.balanceSheets[index] = balanceSheet;
|
state.balanceSheet.sheets[index] = balanceSheet;
|
||||||
} else {
|
} else {
|
||||||
state.balanceSheets.push(balanceSheet);
|
state.balanceSheet.sheets.push(balanceSheet);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
[t.BALANCE_SHEET_LOADING]: (state, action) => {
|
||||||
|
state.balanceSheet.loading = !!action.loading;
|
||||||
|
},
|
||||||
|
|
||||||
[t.TRAIL_BALANCE_STATEMENT_SET]: (state, action) => {
|
[t.TRAIL_BALANCE_STATEMENT_SET]: (state, action) => {
|
||||||
const index = getFinancialSheetIndexByQuery(state.trialBalance.sheets, action.query);
|
const index = getFinancialSheetIndexByQuery(state.trialBalance.sheets, action.query);
|
||||||
const trailBalanceSheet = {
|
const trailBalanceSheet = {
|
||||||
@@ -139,6 +181,10 @@ export default createReducer(initialState, {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
[t.GENERAL_LEDGER_SHEET_LOADING]: (state, action) => {
|
||||||
|
state.generalLedger.loading = !!action.loading;
|
||||||
|
},
|
||||||
|
|
||||||
[t.PROFIT_LOSS_SHEET_SET]: (state, action) => {
|
[t.PROFIT_LOSS_SHEET_SET]: (state, action) => {
|
||||||
const index = getFinancialSheetIndexByQuery(state.profitLoss.sheets, action.query);
|
const index = getFinancialSheetIndexByQuery(state.profitLoss.sheets, action.query);
|
||||||
|
|
||||||
@@ -146,6 +192,7 @@ export default createReducer(initialState, {
|
|||||||
query: action.query,
|
query: action.query,
|
||||||
profitLoss: action.profitLoss,
|
profitLoss: action.profitLoss,
|
||||||
columns: action.columns,
|
columns: action.columns,
|
||||||
|
tableRows: mapProfitLossToTableRows(action.profitLoss),
|
||||||
};
|
};
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
state.profitLoss.sheets[index] = profitLossSheet;
|
state.profitLoss.sheets[index] = profitLossSheet;
|
||||||
|
|||||||
@@ -38,97 +38,19 @@ export const getFinancialSheetColumns = (sheets, index) => {
|
|||||||
* @param {array} sheets
|
* @param {array} sheets
|
||||||
* @param {number} index
|
* @param {number} index
|
||||||
*/
|
*/
|
||||||
export const getFinancialSheetsQuery = (sheets, index) => {
|
export const getFinancialSheetQuery = (sheets, index) => {
|
||||||
const sheet = getFinancialSheet(sheets, index);
|
const sheet = getFinancialSheet(sheets, index);
|
||||||
return (sheet && sheet.query) ? sheet.columns : {};
|
return (sheet && sheet.query) ? sheet.query : {};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Balance Sheet.
|
export const getFinancialSheetAccounts = (sheets, index) => {
|
||||||
export const getBalanceSheetByQuery = (balanceSheets, query) => {
|
const sheet = getFinancialSheet(sheets, index);
|
||||||
return balanceSheets.find(balanceSheet => {
|
return (sheet && sheet.accounts) ? sheet.accounts : [];
|
||||||
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 getFinancialSheetTableRows = (sheets, index) => {
|
||||||
export const getTrialBalanceSheetIndex = (trialBalanceSheets, query) => {
|
const sheet = getFinancialSheet(sheets, index);
|
||||||
return trialBalanceSheets.find((trialBalanceSheet) => {
|
return (sheet && sheet.tableRows) ? sheet.tableRows : [];
|
||||||
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 : [];
|
|
||||||
};
|
};
|
||||||
@@ -2,9 +2,14 @@
|
|||||||
|
|
||||||
export default {
|
export default {
|
||||||
GENERAL_LEDGER_STATEMENT_SET: 'GENERAL_LEDGER_STATEMENT_SET',
|
GENERAL_LEDGER_STATEMENT_SET: 'GENERAL_LEDGER_STATEMENT_SET',
|
||||||
|
GENERAL_LEDGER_SHEET_LOADING: 'GENERAL_LEDGER_SHEET_LOADING',
|
||||||
|
|
||||||
BALANCE_SHEET_STATEMENT_SET: 'BALANCE_SHEET_STATEMENT_SET',
|
BALANCE_SHEET_STATEMENT_SET: 'BALANCE_SHEET_STATEMENT_SET',
|
||||||
|
BALANCE_SHEET_LOADING: 'BALANCE_SHEET_LOADING',
|
||||||
|
|
||||||
TRAIL_BALANCE_STATEMENT_SET: 'TRAIL_BALANCE_STATEMENT_SET',
|
TRAIL_BALANCE_STATEMENT_SET: 'TRAIL_BALANCE_STATEMENT_SET',
|
||||||
TRIAL_BALANCE_SHEET_LOADING: 'TRIAL_BALANCE_SHEET_LOADING',
|
TRIAL_BALANCE_SHEET_LOADING: 'TRIAL_BALANCE_SHEET_LOADING',
|
||||||
|
|
||||||
JOURNAL_SHEET_SET: 'JOURNAL_SHEET_SET',
|
JOURNAL_SHEET_SET: 'JOURNAL_SHEET_SET',
|
||||||
JOURNAL_SHEET_LOADING: 'JOURNAL_SHEET_LOADING',
|
JOURNAL_SHEET_LOADING: 'JOURNAL_SHEET_LOADING',
|
||||||
|
|
||||||
|
|||||||
@@ -139,7 +139,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.no-results{
|
.no-results{
|
||||||
|
|
||||||
color: #666;
|
color: #666;
|
||||||
|
|
||||||
.td{
|
.td{
|
||||||
@@ -149,6 +148,15 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.has-sticky-header{
|
||||||
|
|
||||||
|
.thead{
|
||||||
|
.tr .th{
|
||||||
|
position: sticky;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
&--financial-report{
|
&--financial-report{
|
||||||
|
|
||||||
.thead{
|
.thead{
|
||||||
|
|||||||
@@ -30,7 +30,7 @@
|
|||||||
min-height: 32px;
|
min-height: 32px;
|
||||||
background-color: #E6EFFB;
|
background-color: #E6EFFB;
|
||||||
color: #555555;
|
color: #555555;
|
||||||
box-shadow: 0 0 0;
|
box-shadow: 0 0 0 transparent;
|
||||||
|
|
||||||
.form-group--select-list &{
|
.form-group--select-list &{
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
@@ -38,7 +38,7 @@
|
|||||||
&,
|
&,
|
||||||
&:hover{
|
&:hover{
|
||||||
background: #fff;
|
background: #fff;
|
||||||
box-shadow: 0 0 0;
|
box-shadow: 0 0 0 transparent;
|
||||||
border: 1px solid #ced4da;
|
border: 1px solid #ced4da;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
|
|
||||||
&,
|
&,
|
||||||
&:hover{
|
&:hover{
|
||||||
box-shadow: 0 0 0;
|
box-shadow: 0 0 0 transparent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -95,3 +95,109 @@ label{
|
|||||||
color: #8D8D8D;
|
color: #8D8D8D;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
///@extend
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
.#{$ns}-control {
|
||||||
|
|
||||||
|
input:checked ~ .#{$ns}-control-indicator {
|
||||||
|
box-shadow: 0 0 0 transparent;
|
||||||
|
background-color: transparent;
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
&:hover input:checked ~ .#{$ns}-control-indicator {
|
||||||
|
box-shadow: 0 0 0 transparent;
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
input:not(:disabled):active:checked ~ .#{$ns}-control-indicator {
|
||||||
|
box-shadow: 0 0 0 transparent;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
input:disabled:checked ~ .#{$ns}-control-indicator {
|
||||||
|
box-shadow: none;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.#{$ns}-disabled {
|
||||||
|
cursor: not-allowed;
|
||||||
|
color: $pt-text-color-disabled;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.#{$ns}-inline {
|
||||||
|
display: inline-block;
|
||||||
|
margin-right: $pt-grid-size * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.#{$ns}-control-indicator {
|
||||||
|
box-shadow: 0 0 0 transparent;
|
||||||
|
background-clip: padding-box;
|
||||||
|
background-color: transparent;
|
||||||
|
background-image: none;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover .#{$ns}-control-indicator {
|
||||||
|
background-color: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:not(:disabled):active ~ .#{$ns}-control-indicator {
|
||||||
|
box-shadow: 0 0 0 transparent;
|
||||||
|
background: transparent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Radio
|
||||||
|
|
||||||
|
Markup:
|
||||||
|
<label class="#{$ns}-control #{$ns}-radio {{.modifier}}">
|
||||||
|
<input type="radio" name="docs-radio-regular" {{:modifier}} />
|
||||||
|
<span class="#{$ns}-control-indicator"></span>
|
||||||
|
Radio
|
||||||
|
</label>
|
||||||
|
|
||||||
|
:checked - Selected
|
||||||
|
:disabled - Disabled. Also add <code>.#{$ns}-disabled</code> to <code>.#{$ns}-control</code> to change text color (not shown below).
|
||||||
|
.#{$ns}-align-right - Right-aligned indicator
|
||||||
|
.#{$ns}-large - Large
|
||||||
|
|
||||||
|
Styleguide radio
|
||||||
|
*/
|
||||||
|
&.#{$ns}-radio {
|
||||||
|
|
||||||
|
.#{$ns}-control-indicator{
|
||||||
|
border: 2px solid #cecece;
|
||||||
|
|
||||||
|
&::before{
|
||||||
|
height: 14px;
|
||||||
|
width: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked ~ .#{$ns}-control-indicator{
|
||||||
|
border-color: #137cbd;
|
||||||
|
|
||||||
|
&::before {
|
||||||
|
background-image: radial-gradient(#137cbd 40%, transparent 40%);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
input:checked:disabled ~ .#{$ns}-control-indicator::before {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus ~ .#{$ns}-control-indicator {
|
||||||
|
-moz-outline-radius: $control-indicator-size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -7,26 +7,46 @@
|
|||||||
padding: 25px 26px 25px;
|
padding: 25px 26px 25px;
|
||||||
background: #FDFDFD;
|
background: #FDFDFD;
|
||||||
|
|
||||||
.bp3-form-group .bp3-label{
|
.bp3-form-group,
|
||||||
font-weight: 500;
|
.radio-group---accounting-basis{
|
||||||
font-size: 13px;
|
|
||||||
color: #444;
|
.bp3-label{
|
||||||
|
font-weight: 500;
|
||||||
|
font-size: 13px;
|
||||||
|
color: #444;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.bp3-button.button--submit-filter{
|
||||||
|
min-height: 34px;
|
||||||
|
padding-left: 16px;
|
||||||
|
padding-right: 16px;
|
||||||
|
}
|
||||||
|
.radio-group---accounting-basis{
|
||||||
|
.bp3-label{
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&__body{
|
&__body{
|
||||||
padding-left: 20px;
|
padding-left: 20px;
|
||||||
padding-right: 20px;
|
padding-right: 20px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.financial-sheet{
|
.financial-sheet{
|
||||||
border: 1px solid #E2E2E2;
|
border: 1px solid #E2E2E2;
|
||||||
min-width: 640px;
|
min-width: 640px;
|
||||||
width: 0;
|
width: auto;
|
||||||
padding: 20px;
|
padding: 30px 20px;
|
||||||
padding-top: 30px;
|
max-width: 100%;
|
||||||
margin: 35px auto;
|
margin: 35px auto;
|
||||||
|
min-height: 400px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
|
||||||
&__title{
|
&__title{
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -57,14 +77,24 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&__accounting-basis{
|
&__basis{
|
||||||
|
color: #888;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: auto;
|
||||||
|
padding-top: 16px;
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
.dashboard__loading-indicator{
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--expended{
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
&--trial-balance{
|
&--trial-balance{
|
||||||
min-width: 720px;
|
min-width: 720px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&--general-ledger,
|
&--general-ledger,
|
||||||
&--journal{
|
&--journal{
|
||||||
width: auto;
|
width: auto;
|
||||||
@@ -73,11 +103,8 @@
|
|||||||
margin-top: 10px;
|
margin-top: 10px;
|
||||||
border-color: #EEEDED;
|
border-color: #EEEDED;
|
||||||
}
|
}
|
||||||
|
|
||||||
&--journal{
|
&--journal{
|
||||||
|
|
||||||
.financial-sheet__table{
|
.financial-sheet__table{
|
||||||
|
|
||||||
.tbody{
|
.tbody{
|
||||||
.tr .td{
|
.tr .td{
|
||||||
padding: 0.4rem;
|
padding: 0.4rem;
|
||||||
@@ -96,4 +123,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&--profit-loss-sheet{
|
||||||
|
|
||||||
|
.financial-sheet__table{
|
||||||
|
.tbody{
|
||||||
|
.account_code.td{
|
||||||
|
color: #666;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row--income_total,
|
||||||
|
.row--expense_total,
|
||||||
|
.row--net_income{
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
.total.td{
|
||||||
|
border-bottom-color: #555;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -112,3 +112,23 @@ export const parseDateRangeQuery = (keyword) => {
|
|||||||
to_date: moment().endOf(query.range).toDate(),
|
to_date: moment().endOf(query.range).toDate(),
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export const defaultExpanderReducer = (tableRows, level) => {
|
||||||
|
let currentLevel = 1;
|
||||||
|
const expended = [];
|
||||||
|
|
||||||
|
const walker = (rows, parentIndex = null) => {
|
||||||
|
return rows.forEach((row, index) => {
|
||||||
|
const _index = parentIndex ? `${parentIndex}.${index}` : `${index}`;
|
||||||
|
expended[_index] = true;
|
||||||
|
|
||||||
|
if (row.children && currentLevel < level) {
|
||||||
|
walker(row.children, _index);
|
||||||
|
}
|
||||||
|
currentLevel++;
|
||||||
|
}, {});
|
||||||
|
};
|
||||||
|
walker(tableRows);
|
||||||
|
return expended;
|
||||||
|
}
|
||||||
@@ -274,7 +274,9 @@ export default {
|
|||||||
query('accounting_method').optional().isIn(['cash', 'accural']),
|
query('accounting_method').optional().isIn(['cash', 'accural']),
|
||||||
query('from_date').optional(),
|
query('from_date').optional(),
|
||||||
query('to_date').optional(),
|
query('to_date').optional(),
|
||||||
query('display_columns_by').optional().isIn(['total', 'year', 'month', 'week', 'day', 'quarter']),
|
query('display_columns_type').optional().isIn(['date_periods', 'total']),
|
||||||
|
query('display_columns_by').optional({ nullable: true, checkFalsy: true })
|
||||||
|
.isIn(['year', 'month', 'week', 'day', 'quarter']),
|
||||||
query('number_format.no_cents').optional().isBoolean().toBoolean(),
|
query('number_format.no_cents').optional().isBoolean().toBoolean(),
|
||||||
query('number_format.divide_1000').optional().isBoolean().toBoolean(),
|
query('number_format.divide_1000').optional().isBoolean().toBoolean(),
|
||||||
query('none_zero').optional().isBoolean().toBoolean(),
|
query('none_zero').optional().isBoolean().toBoolean(),
|
||||||
@@ -288,7 +290,8 @@ export default {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
const filter = {
|
const filter = {
|
||||||
display_columns_by: 'total',
|
display_columns_type: 'total',
|
||||||
|
display_columns_by: '',
|
||||||
from_date: moment().startOf('year').format('YYYY-MM-DD'),
|
from_date: moment().startOf('year').format('YYYY-MM-DD'),
|
||||||
to_date: moment().endOf('year').format('YYYY-MM-DD'),
|
to_date: moment().endOf('year').format('YYYY-MM-DD'),
|
||||||
number_format: {
|
number_format: {
|
||||||
@@ -299,7 +302,6 @@ export default {
|
|||||||
basis: 'cash',
|
basis: 'cash',
|
||||||
...req.query,
|
...req.query,
|
||||||
};
|
};
|
||||||
|
|
||||||
const balanceSheetTypes = await AccountType.query().where('balance_sheet', true);
|
const balanceSheetTypes = await AccountType.query().where('balance_sheet', true);
|
||||||
|
|
||||||
// Fetch all balance sheet accounts.
|
// Fetch all balance sheet accounts.
|
||||||
@@ -317,91 +319,76 @@ export default {
|
|||||||
|
|
||||||
// Account balance formmatter based on the given query.
|
// Account balance formmatter based on the given query.
|
||||||
const balanceFormatter = formatNumberClosure(filter.number_format);
|
const balanceFormatter = formatNumberClosure(filter.number_format);
|
||||||
const filterDateType = filter.display_columns_by === 'total'
|
const comparatorDateType = filter.display_columns_type === 'total'
|
||||||
? 'day' : filter.display_columns_by;
|
? 'day' : filter.display_columns_by;
|
||||||
|
|
||||||
// Gets the date range set from start to end date.
|
const dateRangeSet = (filter.display_columns_type === 'date_periods')
|
||||||
const dateRangeSet = dateRangeCollection(
|
? dateRangeCollection(
|
||||||
filter.from_date,
|
filter.from_date, filter.to_date, comparatorDateType,
|
||||||
filter.to_date,
|
) : [];
|
||||||
filterDateType,
|
|
||||||
);
|
const totalPeriods = (account) => {
|
||||||
// Retrieve the asset balance sheet.
|
// Gets the date range set from start to end date.
|
||||||
const assets = accounts
|
return {
|
||||||
.filter((account) => (
|
total_periods: dateRangeSet.map((date) => {
|
||||||
account.type.normal === 'debit'
|
const balance = journalEntries.getClosingBalance(account.id, date, comparatorDateType);
|
||||||
&& (account.transactions.length > 0 || !filter.none_zero)
|
return {
|
||||||
))
|
date,
|
||||||
.map((account) => {
|
formatted_amount: balanceFormatter(balance),
|
||||||
|
amount: balance,
|
||||||
|
};
|
||||||
|
}),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const accountsMapper = (balanceSheetAccounts) => {
|
||||||
|
return balanceSheetAccounts.map((account) => {
|
||||||
// Calculates the closing balance to the given date.
|
// Calculates the closing balance to the given date.
|
||||||
const closingBalance = journalEntries.getClosingBalance(account.id, filter.to_date);
|
const closingBalance = journalEntries.getClosingBalance(account.id, filter.to_date);
|
||||||
const type = filter.display_columns_by;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...pick(account, ['id', 'index', 'name', 'code']),
|
...pick(account, ['id', 'index', 'name', 'code']),
|
||||||
...(type !== 'total') ? {
|
|
||||||
periods_balance: dateRangeSet.map((date) => {
|
|
||||||
const balance = journalEntries.getClosingBalance(account.id, date, filterDateType);
|
|
||||||
|
|
||||||
return {
|
// Date periods when display columns.
|
||||||
date,
|
...(filter.display_columns_type === 'date_periods') && totalPeriods(account),
|
||||||
formatted_amount: balanceFormatter(balance),
|
|
||||||
amount: balance,
|
total: {
|
||||||
};
|
|
||||||
}),
|
|
||||||
} : {},
|
|
||||||
balance: {
|
|
||||||
formatted_amount: balanceFormatter(closingBalance),
|
formatted_amount: balanceFormatter(closingBalance),
|
||||||
amount: closingBalance,
|
amount: closingBalance,
|
||||||
date: filter.to_date,
|
date: filter.to_date,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
};
|
||||||
|
// Retrieve all assets accounts.
|
||||||
|
const assetsAccounts = accounts.filter((account) => (
|
||||||
|
account.type.normal === 'debit'
|
||||||
|
&& (account.transactions.length > 0 || !filter.none_zero)));
|
||||||
|
|
||||||
|
// Retrieve all liability accounts.
|
||||||
|
const liabilitiesAccounts = accounts.filter((account) => (
|
||||||
|
account.type.normal === 'credit'
|
||||||
|
&& (account.transactions.length > 0 || !filter.none_zero)));
|
||||||
|
|
||||||
|
// Retrieve the asset balance sheet.
|
||||||
|
const assets = accountsMapper(assetsAccounts);
|
||||||
|
|
||||||
// Retrieve liabilities and equity balance sheet.
|
// Retrieve liabilities and equity balance sheet.
|
||||||
const liabilitiesEquity = accounts
|
const liabilitiesEquity = accountsMapper(liabilitiesAccounts);
|
||||||
.filter((account) => (
|
|
||||||
account.type.normal === 'credit'
|
|
||||||
&& (account.transactions.length > 0 || !filter.none_zero)
|
|
||||||
))
|
|
||||||
.map((account) => {
|
|
||||||
// Calculates the closing balance to the given date.
|
|
||||||
const closingBalance = journalEntries.getClosingBalance(account.id, filter.to_date);
|
|
||||||
const type = filter.display_columns_by;
|
|
||||||
|
|
||||||
return {
|
|
||||||
...pick(account, ['id', 'index', 'name', 'code']),
|
|
||||||
...(type !== 'total') ? {
|
|
||||||
periods_balance: dateRangeSet.map((date) => {
|
|
||||||
const balance = journalEntries.getClosingBalance(account.id, date, filterDateType);
|
|
||||||
return {
|
|
||||||
date,
|
|
||||||
formatted_amount: balanceFormatter(balance),
|
|
||||||
amount: balance,
|
|
||||||
};
|
|
||||||
}),
|
|
||||||
} : {},
|
|
||||||
balance: {
|
|
||||||
formatted_amount: balanceFormatter(closingBalance),
|
|
||||||
amount: closingBalance,
|
|
||||||
date: filter.to_date,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return res.status(200).send({
|
return res.status(200).send({
|
||||||
query: { ...filter },
|
query: { ...filter },
|
||||||
columns: { ...dateRangeSet },
|
columns: { ...dateRangeSet },
|
||||||
balance_sheet: {
|
accounts: [
|
||||||
assets: {
|
{
|
||||||
title: 'Assets',
|
name: 'Assets',
|
||||||
accounts: [...assets],
|
children: [...assets],
|
||||||
},
|
},
|
||||||
liabilities_equity: {
|
{
|
||||||
title: 'Liabilities & Equity',
|
name: 'Liabilities & Equity',
|
||||||
accounts: [...liabilitiesEquity],
|
children: [...liabilitiesEquity],
|
||||||
},
|
},
|
||||||
},
|
],
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -492,9 +479,8 @@ export default {
|
|||||||
query('display_columns_type').optional().isIn([
|
query('display_columns_type').optional().isIn([
|
||||||
'total', 'date_periods',
|
'total', 'date_periods',
|
||||||
]),
|
]),
|
||||||
query('display_columns_by').optional().isIn([
|
query('display_columns_by').optional({ nullable: true, checkFalsy: true })
|
||||||
'year', 'month', 'week', 'day', 'quarter',
|
.isIn(['year', 'month', 'week', 'day', 'quarter']),
|
||||||
]),
|
|
||||||
],
|
],
|
||||||
async handler(req, res) {
|
async handler(req, res) {
|
||||||
const validationErrors = validationResult(req);
|
const validationErrors = validationResult(req);
|
||||||
|
|||||||
@@ -363,7 +363,7 @@ describe('routes: `/financial_statements`', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('routes: `financial_statements/balance_sheet`', () => {
|
describe.only('routes: `financial_statements/balance_sheet`', () => {
|
||||||
it('Should response unauthorzied in case the user was not authorized.', async () => {
|
it('Should response unauthorzied in case the user was not authorized.', async () => {
|
||||||
const res = await request()
|
const res = await request()
|
||||||
.get('/api/financial_statements/balance_sheet')
|
.get('/api/financial_statements/balance_sheet')
|
||||||
@@ -406,21 +406,23 @@ describe('routes: `/financial_statements`', () => {
|
|||||||
expect(res.body.balance_sheet.liabilities_equity.accounts).to.be.a('array');
|
expect(res.body.balance_sheet.liabilities_equity.accounts).to.be.a('array');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Should retrieve assets/liabilities total balance between the given date range.', async () => {
|
it.only('Should retrieve assets/liabilities total balance between the given date range.', async () => {
|
||||||
const res = await request()
|
const res = await request()
|
||||||
.get('/api/financial_statements/balance_sheet')
|
.get('/api/financial_statements/balance_sheet')
|
||||||
.set('x-access-token', loginRes.body.token)
|
.set('x-access-token', loginRes.body.token)
|
||||||
.query({
|
.query({
|
||||||
display_columns_by: 'total',
|
display_columns_type: 'total',
|
||||||
from_date: '2012-01-01',
|
from_date: '2012-01-01',
|
||||||
to_date: '2032-02-02',
|
to_date: '2032-02-02',
|
||||||
})
|
})
|
||||||
.send();
|
.send();
|
||||||
|
|
||||||
expect(res.body.balance_sheet.assets.accounts[0].balance).deep.equals({
|
console.log(res.body.balance_sheet.assets.accounts);
|
||||||
|
|
||||||
|
expect(res.body.balance_sheet.assets.accounts[0].total).deep.equals({
|
||||||
amount: 4000, formatted_amount: 4000, date: '2032-02-02',
|
amount: 4000, formatted_amount: 4000, date: '2032-02-02',
|
||||||
});
|
});
|
||||||
expect(res.body.balance_sheet.liabilities_equity.accounts[0].balance).deep.equals({
|
expect(res.body.balance_sheet.liabilities_equity.accounts[0].total).deep.equals({
|
||||||
amount: 2000, formatted_amount: 2000, date: '2032-02-02',
|
amount: 2000, formatted_amount: 2000, date: '2032-02-02',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import knex from '@/database/knex';
|
|||||||
|
|
||||||
let loginRes;
|
let loginRes;
|
||||||
|
|
||||||
describe.only('routes: /item_categories/', () => {
|
describe('routes: /item_categories/', () => {
|
||||||
beforeEach(async () => {
|
beforeEach(async () => {
|
||||||
loginRes = await login();
|
loginRes = await login();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user