WIP financial statements.

This commit is contained in:
Ahmed Bouhuolia
2020-03-31 16:30:38 +02:00
parent da05239e84
commit 1bf837ae17
26 changed files with 442 additions and 148 deletions

View File

@@ -16,6 +16,7 @@
"@testing-library/user-event": "^7.2.1",
"@typescript-eslint/eslint-plugin": "^2.10.0",
"@typescript-eslint/parser": "^2.10.0",
"accounting": "^0.4.1",
"axios": "^0.19.2",
"babel-eslint": "10.0.3",
"babel-jest": "^24.9.0",
@@ -45,6 +46,7 @@
"jest-environment-jsdom-fourteen": "1.0.1",
"jest-resolve": "24.9.0",
"jest-watch-typeahead": "0.4.2",
"js-money": "^0.6.3",
"lodash": "^4.17.15",
"mini-css-extract-plugin": "0.9.0",
"moment": "^2.24.0",

View File

@@ -131,7 +131,8 @@ function AccountsDataTable({
columns={columns}
data={accounts}
onFetchData={handleDatatableFetchData}
manualSortBy={true} />
manualSortBy={true}
selectionColumn={true} />
</LoadingIndicator>
);
}

View File

@@ -12,7 +12,6 @@ import {
import {Checkbox} from '@blueprintjs/core';
import classnames from 'classnames';
import Icon from 'components/Icon';
// import { FixedSizeList } from 'react-window'
const IndeterminateCheckbox = React.forwardRef(
({ indeterminate, ...rest }, ref) => {
@@ -23,9 +22,7 @@ const IndeterminateCheckbox = React.forwardRef(
resolvedRef.current.indeterminate = indeterminate
}, [resolvedRef, indeterminate])
return (
<Checkbox ref={resolvedRef} {...rest} />
);
return (<Checkbox ref={resolvedRef} {...rest} />);
}
);
@@ -35,7 +32,9 @@ export default function DataTable({
loading,
onFetchData,
onSelectedRowsChange,
manualSortBy = 'false'
manualSortBy = 'false',
selectionColumn = false,
className
}) {
const {
getTableProps,
@@ -51,8 +50,8 @@ export default function DataTable({
nextPage,
previousPage,
setPageSize,
selectedFlatRows,
// Get the state from the instance
state: { pageIndex, pageSize, sortBy, selectedRowIds },
} = useTable(
@@ -77,7 +76,7 @@ export default function DataTable({
hooks => {
hooks.visibleColumns.push(columns => [
// Let's make a column for selection
{
...(selectionColumn) ? [{
id: 'selection',
disableResizing: true,
minWidth: 35,
@@ -97,23 +96,19 @@ export default function DataTable({
<IndeterminateCheckbox {...row.getToggleRowSelectedProps()} />
</div>
),
},
}] : [],
...columns,
])
}
);
// Debounce our onFetchData call for 100ms
const onFetchDataDebounced = useAsyncDebounce(onFetchData, 100);
const onSelectRowsDebounced = useAsyncDebounce(onSelectedRowsChange, 250);
// When these table states change, fetch new data!
useEffect(() => {
onFetchDataDebounced({ pageIndex, pageSize, sortBy })
}, []);
onFetchData && onFetchData({ pageIndex, pageSize, sortBy })
}, [pageIndex, pageSize, sortBy]);
return (
<div className={'bigcapital-datatable'}>
<div className={classnames('bigcapital-datatable', className)}>
<div {...getTableProps()} className="table">
<div className="thead">
{headerGroups.map(headerGroup => (
@@ -157,8 +152,7 @@ export default function DataTable({
className: classnames(cell.column.className || '', 'td'),
})}>{ cell.render('Cell') }</div>
})}
</div>
)
</div>)
})}
</div>
</div>

View File

@@ -1,26 +1,35 @@
import React, { Children } from 'react';
import moment from 'moment';
import classnames from 'classnames';
import LoadingIndicator from 'components/LoadingIndicator';
export default function FinancialSheet({
companyTitle,
sheetType,
date,
children,
accountingBasis
accountingBasis,
name,
loading,
}) {
const formattedDate = moment(date).format('DD MMMM YYYY')
const nameModifer = name ? `financial-sheet--${name}` : '';
return (
<div class="financial-sheet">
<h1 class="financial-sheet__title">{ companyTitle }</h1>
<h6 class="financial-sheet__sheet-type">{ sheetType }</h6>
<span class="financial-sheet__date">{ date }</span>
<div className={classnames('financial-sheet', nameModifer)}>
<LoadingIndicator loading={loading}>
<h1 class="financial-sheet__title">{ companyTitle }</h1>
<h6 class="financial-sheet__sheet-type">{ sheetType }</h6>
<div class="financial-sheet__date">As of { formattedDate }</div>
<div class="financial-sheet__table">
{ children }
</div>
<div class="financial-sheet__table">
{ children }
</div>
<div class="financial-sheet__accounting-basis">
{ accountingBasis }
</div>
<div class="financial-sheet__accounting-basis">
{ accountingBasis }
</div>
</LoadingIndicator>
</div>
);
}

View File

@@ -4,9 +4,10 @@ import { Spinner } from '@blueprintjs/core';
export default function LoadingIndicator({
loading,
spinnerSize = 40,
children
children,
mount = true,
}) {
const [rendered, setRendered] = useState(false);
const [rendered, setRendered] = useState(mount);
useEffect(() => {
if (!loading) { setRendered(true); }

View File

@@ -0,0 +1,16 @@
import React from 'react';
import Currency from 'js-money/lib/currency';
import accounting from 'accounting';
function formattedAmount(cents, currency) {
const { symbol, decimal_digits: precision } = Currency[currency];
const amount = cents / Math.pow(10, precision);
return accounting.formatMoney(amount, { symbol, precision });
}
export default function Money({ amount, currency }) {
return (
<span>{ formattedAmount(amount, currency) }</span>
);
}

View File

@@ -6,12 +6,15 @@ import {
getTrialBalanceSheetIndex,
getTrialBalanceAccounts,
getTrialBalanceQuery,
getFinancialSheetIndexByQuery,
} 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),
getTrialBalanceSheetIndex: (query) => getFinancialSheetIndexByQuery(state.financialStatements.trialBalance.sheets, query),
getTrialBalanceAccounts: (sheetIndex) => getTrialBalanceAccounts(state.financialStatements.trialBalance.sheets, sheetIndex),
getTrialBalanceQuery: (sheetIndex) => getTrialBalanceQuery(state.financialStatements.trialBalance.sheets, sheetIndex),
trialBalanceSheetLoading: state.financialStatements.trialBalance.loading,
});
export const mapDispatchToProps = (dispatch) => ({

View File

@@ -1,4 +1,4 @@
import React, {useEffect, useMemo, useState} from 'react';
import React, {useEffect, useMemo, useCallback, useState} from 'react';
import DashboardConnect from 'connectors/Dashboard.connector';
import {compose} from 'utils';
import useAsync from 'hooks/async';
@@ -30,39 +30,41 @@ function BalanceSheet({
const fetchHook = useAsync(async () => {
await Promise.all([
fetchBalanceSheet(filter),
fetchBalanceSheet({
...filter,
display_columns_type: 'total',
}),
]);
setReload(false);
});
useEffect(() => {
if (!reload) { return; }
fetchHook.execute();
}, [reload]);
// Handle fetch the data of balance sheet.
const handleFetchData = useCallback(() => { fetchHook.execute(); }, [fetchHook]);
useEffect(() => {
changePageTitle('Balance Sheet');
}, []);
// Retrieve balance sheet index by the given filter query.
const balanceSheetIndex = useMemo(() => {
return getBalanceSheetIndexByQuery(filter);
}, [filter, balanceSheets]);
const balanceSheetIndex = useMemo(() =>
getBalanceSheetIndexByQuery(filter),
[filter, getBalanceSheetIndexByQuery]);
// Retreive balance sheet by the given sheet index.
const balanceSheet = useMemo(() => {
return getBalanceSheetByIndex(balanceSheetIndex);
}, [balanceSheetIndex, balanceSheets]);
const balanceSheet = useMemo(() =>
getBalanceSheetByIndex(balanceSheetIndex),
[balanceSheetIndex, getBalanceSheetByIndex]);
// Handle re-fetch balance sheet after filter change.
const handleFilterSubmit = (filter) => {
const handleFilterSubmit = useCallback((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);
};
}, [setFilter]);
return (
<div class="financial-statement">
<BalanceSheetHeader
@@ -73,7 +75,9 @@ function BalanceSheet({
<LoadingIndicator loading={fetchHook.pending}>
<BalanceSheetTable
balanceSheet={balanceSheet}
balanceSheetIndex={balanceSheetIndex} />
balanceSheetIndex={balanceSheetIndex}
onFetchData={handleFetchData}
asDate={new Date()} />
</LoadingIndicator>
</div>
</div>

View File

@@ -11,6 +11,7 @@ import {
HTMLSelect,
Intent,
Popover,
Classes,
} from "@blueprintjs/core";
import {Select} from '@blueprintjs/select';
import {DateInput} from '@blueprintjs/datetime';
@@ -21,6 +22,7 @@ import {
parseDateRangeQuery,
} from 'utils';
import moment from 'moment';
import Icon from 'components/Icon';
export default function BalanceSheetHeader({
onSubmitFilter,
@@ -111,12 +113,16 @@ export default function BalanceSheetHeader({
</RadioGroup>
</div>
);
const infoIcon = useMemo(() => (<Icon icon="info-circle" iconSize={12} />), []);
return (
<FinancialStatementHeader>
<Row>
<Col sm={3}>
<FormGroup
label={intl.formatMessage({'id': 'report_date_range'})}
labelInfo={infoIcon}
minimal={true}
fill={true}>
@@ -131,6 +137,7 @@ export default function BalanceSheetHeader({
<Col sm={3}>
<FormGroup
label={intl.formatMessage({'id': 'from_date'})}
labelInfo={infoIcon}
minimal={true}
fill={true}>
@@ -146,6 +153,7 @@ export default function BalanceSheetHeader({
<Col sm={3}>
<FormGroup
label={intl.formatMessage({'id': 'to_date'})}
labelInfo={infoIcon}
minimal={true}
fill={true}>
@@ -163,7 +171,8 @@ export default function BalanceSheetHeader({
<Col sm={3}>
<FormGroup
label={'Display report columns'}
className="{'form-group-display-columns-by'}"
labelInfo={infoIcon}
className="form-group-display-columns-by form-group--select-list bp3-fill"
inline={false}>
<Select
@@ -184,6 +193,7 @@ export default function BalanceSheetHeader({
<Col sm={3}>
<FormGroup
label={'Show non-zero or active only'}
className="form-group--select-list bp3-fill"
inline={false}>
<Popover

View File

@@ -1,9 +1,10 @@
import React, {useMemo, useState, 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 Money from 'components/Money';
function BalanceSheetTable({
balanceSheet,
@@ -14,25 +15,32 @@ function BalanceSheetTable({
getBalanceSheetLiabilitiesAccounts,
getBalanceSheetQuery,
}) {
const balanceSheetColumns = useMemo(() => {
return getBalanceSheetColumns(balanceSheetIndex);
}, [getBalanceSheetColumns]);
const balanceSheetQuery = useMemo(() => {
return getBalanceSheetQuery(balanceSheetIndex);
}, [getBalanceSheetQuery])
onFetchData,
asDate,
}) {
const balanceSheetColumns = useMemo(() =>
getBalanceSheetColumns(balanceSheetIndex),
[getBalanceSheetColumns, balanceSheetIndex]);
const balanceSheetQuery = useMemo(() =>
getBalanceSheetQuery(balanceSheetIndex),
[getBalanceSheetQuery, balanceSheetIndex])
const columns = useMemo(() => [
{
// Build our expander column
id: 'expander', // Make sure it has an ID
className: 'expander',
Header: ({
getToggleAllRowsExpandedProps,
isAllRowsExpanded
}) => (
<span {...getToggleAllRowsExpandedProps()}>
{isAllRowsExpanded ? '👇' : '👉'}
<span {...getToggleAllRowsExpandedProps()} className="toggle">
{isAllRowsExpanded ?
(<span class="arrow-down" />) :
(<span class="arrow-right" />)
}
</span>
),
Cell: ({ row }) =>
@@ -47,30 +55,41 @@ function BalanceSheetTable({
// of the row
paddingLeft: `${row.depth * 2}rem`,
},
className: 'toggle',
})}
>
{row.isExpanded ? '👇' : '👉'}
{row.isExpanded ?
(<span class="arrow-down" />) :
(<span class="arrow-right" />)
}
</span>
) : null,
width: 20,
disableResizing: true,
},
{
Header: 'Account Name',
accessor: 'name',
className: "actions",
className: "account_name",
},
{
Header: 'Code',
accessor: 'code',
className: "note",
className: "code",
},
...(balanceSheetQuery &&
balanceSheetQuery.display_columns_by === 'total') ? [
{
Header: 'Total',
accessor: 'balance.formatted_amount',
Cell: ({ cell }) => {
const row = cell.row.original;
if (!row.balance) { return ''; }
return (<Money amount={row.balance.formatted_amount} currency={'USD'} />);
},
className: "credit",
}
]: (balanceSheetColumns.map((column, index) => ({
] : (balanceSheetColumns.map((column, index) => ({
Header: column,
accessor: (row) => {
if (row.periods_balance && row.periods_balance[index]) {
@@ -87,33 +106,32 @@ function BalanceSheetTable({
setData([
{
name: 'Assets',
code: '',
children: [
...getBalanceSheetAssetsAccounts(balanceSheetIndex),
],
children: getBalanceSheetAssetsAccounts(balanceSheetIndex),
},
{
name: 'Liabilies & Equity',
code: '',
children: [
...getBalanceSheetLiabilitiesAccounts(balanceSheetIndex),
]
children: getBalanceSheetLiabilitiesAccounts(balanceSheetIndex),
}
])
}, [])
}, []);
const handleFetchData = useCallback(() => {
onFetchData && onFetchData();
}, [onFetchData]);
return (
<FinancialSheet
companyTitle={'Facebook, Incopration'}
sheetType={'Balance Sheet'}
date={''}>
date={asDate}>
<DataTable
className="bigcapital-datatable--financial-report"
columns={columns}
data={data} />
data={data}
onFetchData={handleFetchData} />
</FinancialSheet>
)
);
}
export default compose(

View File

@@ -1,8 +1,8 @@
import React, { useEffect, useState, useMemo } from 'react';
import React, { useEffect, useCallback, useState, useMemo } from 'react';
import TrialBalanceSheetHeader from "./TrialBalanceSheetHeader";
import LoadingIndicator from 'components/LoadingIndicator';
import TrialBalanceSheetTable from './TrialBalanceSheetTable';
import { useAsync } from 'react-use';
import useAsync from 'hooks/async';
import moment from 'moment';
import {compose} from 'utils';
import TrialBalanceSheetConnect from 'connectors/TrialBalanceSheet.connect';
@@ -13,44 +13,48 @@ function TrialBalanceSheet({
fetchTrialBalanceSheet,
getTrialBalanceSheetIndex,
getTrialBalanceAccounts,
trialBalanceSheetLoading,
}) {
const [filter, setFilter] = useState({
from_date: moment().startOf('year').format('YYYY-MM-DD'),
to_date: moment().endOf('year').format('YYYY-MM-DD'),
basis: 'cash',
basis: 'accural',
none_zero: false,
});
const [reload, setReload] = useState(false);
const fetchHook = useAsync(async () => {
await Promise.all([
fetchTrialBalanceSheet(),
const fetchHook = useAsync((query = filter) => {
return Promise.all([
fetchTrialBalanceSheet(query),
]);
});
}, false);
// handle fetch data of trial balance table.
const handleFetchData = useCallback(() => { fetchHook.execute() }, [fetchHook]);
// Retrieve balance sheet index by the given filter query.
const trialBalanceSheetIndex = useMemo(() => {
return getTrialBalanceSheetIndex(filter);
}, [getTrialBalanceSheetIndex, filter]);
const trialBalanceSheetIndex = useMemo(() =>
getTrialBalanceSheetIndex(filter),
[getTrialBalanceSheetIndex, filter]);
// Retrieve balance sheet accounts bu the given sheet index.
const trialBalanceAccounts = useMemo(() => {
return getTrialBalanceAccounts(trialBalanceSheetIndex);
}, [trialBalanceSheetIndex]);
const trialBalanceAccounts = useMemo(() =>
getTrialBalanceAccounts(trialBalanceSheetIndex),
[getTrialBalanceAccounts, trialBalanceSheetIndex]);
// Change page title of the dashboard.
useEffect(() => {
changePageTitle('Trial Balance Sheet');
}, []);
const handleFilterSubmit = (filter) => {
setFilter({
const handleFilterSubmit = useCallback((filter) => {
const parsedFilter = {
...filter,
from_date: moment(filter.from_date).format('YYYY-MM-DD'),
to_date: moment(filter.to_date).format('YYYY-MM-DD'),
});
setReload(true);
};
};
setFilter(parsedFilter);
fetchHook.execute(parsedFilter);
}, [setFilter, fetchHook]);
return (
<div class="financial-statement">
@@ -59,11 +63,11 @@ function TrialBalanceSheet({
onSubmitFilter={handleFilterSubmit} />
<div class="financial-statement__body">
<LoadingIndicator loading={fetchHook.pending}>
<TrialBalanceSheetTable
trialBalanceSheetAccounts={trialBalanceAccounts}
trialBalanceSheetIndex={trialBalanceSheetIndex} />
</LoadingIndicator>
<TrialBalanceSheetTable
trialBalanceSheetAccounts={trialBalanceAccounts}
trialBalanceSheetIndex={trialBalanceSheetIndex}
onFetchData={handleFetchData}
loading={trialBalanceSheetLoading} />
</div>
</div>
)

View File

@@ -1,4 +1,4 @@
import React, {useState} from 'react';
import React, {useState, useCallback} from 'react';
import FinancialStatementHeader from 'containers/Dashboard/FinancialStatements/FinancialStatementHeader';
import {Row, Col} from 'react-grid-system';
import {
@@ -48,7 +48,7 @@ export default function TrialBalanceSheetHeader({
setFilterByKey(name, date);
};
const handleSubmitClick = () => { onSubmitFilter(filter); };
const handleSubmitClick = useCallback(() => { onSubmitFilter(filter); }, [filter]);
return (
<FinancialStatementHeader>

View File

@@ -1,11 +1,13 @@
import React, {useEffect, useState, useMemo} from 'react';
import React, {useEffect, useState, useCallback, useMemo} from 'react';
import FinancialSheet from 'components/FinancialSheet';
import DataTable from 'components/DataTable';
import Money from 'components/Money';
export default function TrialBalanceSheetTable({
trialBalanceSheetAccounts,
trialBalanceSheetIndex,
onFetchData,
loading,
}) {
const [data, setData] = useState([]);
@@ -13,12 +15,16 @@ export default function TrialBalanceSheetTable({
{
// Build our expander column
id: 'expander', // Make sure it has an ID
className: 'expander',
Header: ({
getToggleAllRowsExpandedProps,
isAllRowsExpanded
}) => (
<span {...getToggleAllRowsExpandedProps()}>
{isAllRowsExpanded ? '👇' : '👉'}
<span {...getToggleAllRowsExpandedProps()} className="toggle">
{isAllRowsExpanded ?
(<span class="arrow-down" />) :
(<span class="arrow-right" />)
}
</span>
),
Cell: ({ row }) =>
@@ -33,48 +39,66 @@ export default function TrialBalanceSheetTable({
// of the row
paddingLeft: `${row.depth * 2}rem`,
},
className: 'toggle',
})}
>
{row.isExpanded ? '👇' : '👉'}
{row.isExpanded ?
(<span class="arrow-down" />) :
(<span class="arrow-right" />)
}
</span>
) : null,
width: 20,
disableResizing: true,
},
{
Header: 'Account Name',
accessor: 'name',
className: "actions",
className: "name",
},
{
Header: 'Code',
accessor: 'code',
className: "note",
className: "code",
width: 120,
},
{
Header: 'Credit',
accessor: 'credit',
accessor: r => (<Money amount={r.credit} currency="USD" />),
className: 'credit',
width: 120,
},
{
Header: 'debit',
accessor: 'debit',
Header: 'Debit',
accessor: r => (<Money amount={r.debit} currency="USD" />),
className: 'debit',
width: 120,
},
{
Header: 'Balance',
accessor: 'balance',
accessor: r => (<Money amount={r.balance} currency="USD" />),
className: 'balance',
width: 120,
}
], []);
const handleFetchData = useCallback(() => {
onFetchData && onFetchData();
}, [onFetchData]);
return (
<FinancialSheet
companyTitle={'Facebook, Incopration'}
sheetType={'Trial Balance Sheet'}
date={''}>
date={new Date()}
name="trial-balance"
loading={loading}>
<DataTable
className="bigcapital-datatable--financial-report"
columns={columns}
data={trialBalanceSheetAccounts} />
data={trialBalanceSheetAccounts}
onFetchData={handleFetchData} />
</FinancialSheet>
);
}

View File

@@ -9,12 +9,12 @@ const useAsync = (asyncFunction, immediate = true) => {
// handles setting state for pending, value, and error.
// useCallback ensures the below useEffect is not called
// on every render, but only if asyncFunction changes.
const execute = useCallback(() => {
const execute = useCallback((...args) => {
setPending(true);
setValue(null);
setError(null);
return asyncFunction()
return asyncFunction(...args)
.then(response => setValue(response))
.catch(error => setError(error))
.finally(() => setPending(false));

View File

@@ -86,5 +86,9 @@ export default {
"sort-down": {
path: ['M41 288h238c21.4 0 32.1 25.9 17 41L177 448c-9.4 9.4-24.6 9.4-33.9 0L24 329c-15.1-15.1-4.4-41 17-41z'],
viewBox: '0 0 320 512'
},
"info-circle": {
path: ['M256 8C119.043 8 8 119.083 8 256c0 136.997 111.043 248 248 248s248-111.003 248-248C504 119.083 392.957 8 256 8zm0 110c23.196 0 42 18.804 42 42s-18.804 42-42 42-42-18.804-42-42 18.804-42 42-42zm56 254c0 6.627-5.373 12-12 12h-88c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h12v-64h-12c-6.627 0-12-5.373-12-12v-24c0-6.627 5.373-12 12-12h64c6.627 0 12 5.373 12 12v100h12c6.627 0 12 5.373 12 12v24z'],
viewBox: '0 0 512 512'
}
}

View File

@@ -28,11 +28,19 @@ export const fetchBalanceSheet = ({ query }) => {
export const fetchTrialBalanceSheet = ({ query }) => {
return (dispatch) => new Promise((resolve, reject) => {
dispatch({
type: t.TRIAL_BALANCE_SHEET_LOADING,
loading: true,
});
ApiService.get('/financial_statements/trial_balance_sheet', { params: query }).then((response) => {
dispatch({
type: t.TRAIL_BALANCE_STATEMENT_SET,
data: response.data,
});
dispatch({
type: t.TRIAL_BALANCE_SHEET_LOADING,
loading: false,
});
resolve(response.data);
}).catch((error) => { reject(error); })
})

View File

@@ -2,13 +2,16 @@ import { createReducer } from '@reduxjs/toolkit';
import t from 'store/types';
import {
getBalanceSheetIndexByQuery,
getTrialBalanceSheetIndex,
getFinancialSheetIndexByQuery,
// getFinancialSheetIndexByQuery,
} from './financialStatements.selectors';
const initialState = {
balanceSheets: [],
trialBalanceSheets: [],
trialBalance: {
sheets: [],
loading: false,
},
generalLedger: [],
journalSheets: [],
};
@@ -30,19 +33,22 @@ export default createReducer(initialState, {
},
[t.TRAIL_BALANCE_STATEMENT_SET]: (state, action) => {
const index = getTrialBalanceSheetIndex(state.trialBalanceSheets, action.query);
const index = getFinancialSheetIndexByQuery(state.trialBalance.sheets, action.query);
const trailBalanceSheet = {
accounts: action.data.accounts,
query: action.data.query,
};
if (index !== -1) {
state.trialBalanceSheets[index] = trailBalanceSheet;
state.trialBalance.sheets[index] = trailBalanceSheet;
} else {
state.trailBalanceSheet.push(trailBalanceSheet);
state.trialBalance.sheets.push(trailBalanceSheet);
}
},
[t.TRIAL_BALANCE_SHEET_LOADING]: (state, action) => {
state.trialBalance.loading = !!action.loading;
},
[t.JOURNAL_SHEET_SET]: (state, action) => {
const index = getFinancialSheetIndexByQuery(state.journalSheets, action.query);
console.log(index, 'INDEX');

View File

@@ -4,5 +4,6 @@ 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',
TRIAL_BALANCE_SHEET_LOADING: 'TRIAL_BALANCE_SHEET_LOADING',
JOURNAL_SHEET_SET: 'JOURNAL_SHEET_SET',
}

View File

@@ -20,6 +20,7 @@ $pt-font-family: Noto Sans, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto,
// Objects
@import "objects/form";
@import "objects/typography";
@import "objects/buttons";
// Components
@import "components/data-table";

View File

@@ -1,8 +1,6 @@
.bigcapital-datatable{
.bigcapital-datatable{
display: block;
// max-width: 100%;
overflow-x: auto;
overflow-y: hidden;
@@ -18,8 +16,6 @@
overflow-x: hidden;
.th{
padding: 1rem 1.5rem;
background: #F8FAFA;
font-size: 14px;
@@ -78,7 +74,7 @@
.inner-resizer{
height: 100%;
width: 1px;
background: #ececec;
border-left: 1px solid #ececec;
margin: 0 auto;
}
@@ -104,6 +100,58 @@
border-radius: 2px;
}
}
.tr .th.expander,
.tr .td.expander{
padding: 0;
.toggle{
cursor: pointer;
display: block;
padding: 14px 8px;
padding-left: 0;
margin-left: 4px;
}
.arrow-right{
width: 0;
height: 0;
border-top: 5px solid transparent;
border-bottom: 5px solid transparent;
border-left: 8px solid #acacac;
display: block;
}
.arrow-down{
width: 0;
height: 0;
border-left: 5px solid transparent;
border-right: 5px solid transparent;
border-top: 8px solid #acacac;
display: block;
}
+ .td,
+ .th{
padding-left: 0;
}
}
}
&--financial-report{
.thead{
.tr .th{
background: transparent;
border-top: 1px solid #666;
border-bottom: 1px solid #666;
padding: 10px 1.5rem;
color: #222;
}
}
}
}

View File

@@ -0,0 +1,58 @@
.form-group--select-list{
.bp3-button{
border-radius: 0;
&,
&:hover{
background: #fff;
box-shadow: 0 0 0;
border: 1px solid #ced4da;
}
}
}
.form-group--select-list.bp3-fill{
.bp3-popover-wrapper{
&,
.bp3-popover-target{
width: 100%;
}
.bp3-button{
width: 100%;
justify-content: space-between;
color: #333;
}
}
}
.form-group--select-list{
.bp3-popover-open{
.bp3-button{
border-color: #80bdff;
}
}
}
.bp3-button{
min-width: 32px;
min-height: 32px;
&.bp3-intent-primary,
&.bp3-intent-success,
&.bp3-intent-danger,
&.bp3-intent-warning{
&,
&:hover{
box-shadow: 0 0 0;
}
}
}

View File

@@ -17,15 +17,22 @@ label{
}
.#{$ns}-input{
box-shadow: 0 0 0 0 rgba(19, 124, 189, 0),
0 0 0 0 rgba(19, 124, 189, 0),
inset 0 0 0 1px rgba(16, 22, 26, 0.1),
inset 0 1px 1px rgba(16, 22, 26, 0.15);
box-shadow: 0 0 0;
border: 1px solid #ced4da;
border-radius: 0;
height: 32px;
line-height: 32px;
color: #333;
&:focus,
&.bp3-active{
box-shadow: 0 0 0 .2rem rgba(0,123,255,.25);
border-color: #80bdff;
}
}
.#{$ns}-form-group{
margin-bottom: 20px;
&.#{$ns}-intent-danger{
select{
@@ -36,4 +43,51 @@ label{
inset 0 1px 1px rgba(16, 22, 26, 0.2);
}
}
.#{$ns}-label{
margin-bottom: 6px;
.#{$ns}-icon-info-circle{
margin-left: 3px;
position: relative;
top: -1px;
color: #A1B2C5;
}
}
}
.#{$ns}-button:not([class*=".#{$ns}-intent-"]) {
background-image: none;
}
.#{$ns}-html-select select,
.#{$ns}-select select{
background-image: none;
border-radius: 0;
&,
&:hover{
background: #fff;
box-shadow: 0 0 0;
border: 1px solid #ced4da;
}
&:focus{
box-shadow: 0 0 0 .2rem rgba(0,123,255,.25);
border-color: #80bdff;
}
}
.bp3-datepicker-caption select{
&,
&:hover{
border-color: transparent;
}
}
.form-group--select-list{
.#{$ns}-icon-caret-down{
color: #8D8D8D;
}
}

View File

@@ -1,4 +1,9 @@
body{
color: #212529;
}
.#{$ns}-heading{
font-weight: 300;
}

View File

@@ -4,8 +4,14 @@
.financial-statement{
&__header{
padding: 30px;
padding: 25px 26px 25px;
background: #FDFDFD;
.bp3-form-group .bp3-label{
font-weight: 500;
font-size: 13px;
color: #444;
}
}
&__body{
@@ -21,28 +27,44 @@
margin-left: auto;
margin-right: auto;
padding: 20px;
margin-top: 40px;
padding-top: 30px;
margin-top: 35px;
&__title{
margin: 0;
font-weight: 200;
font-size: 22px;
color: #222;
text-align: center;
}
&__sheet-type{
text-align: center;
margin: 0;
font-size: 15px;
font-weight: 400;
color: #666;
margin-top: 6px;
}
&__date{
text-align: center;
color: #888;
margin-top: 6px;
}
&__table{
margin-top: 24px;
.tbody{
.code.td{
color: #777;
}
}
}
&__accounting-basis{
}
&--trial-balance{
min-width: 720px;
}
}

View File

@@ -74,7 +74,7 @@ factory.define('manual_journal', 'manual_journals', async () => {
});
factory.define('item_category', 'items_categories', () => ({
label: faker.name.firstName(),
name: faker.name.firstName(),
description: faker.lorem.text(),
parent_category_id: null,
}));

View File

@@ -414,10 +414,10 @@ export default {
query('basis').optional(),
query('from_date').optional().isISO8601(),
query('to_date').optional().isISO8601(),
query('number_format.no_cents').optional().isBoolean(),
query('number_format.1000_divide').optional().isBoolean(),
query('number_format.no_cents').optional().isBoolean().toBoolean(),
query('number_format.1000_divide').optional().isBoolean().toBoolean(),
query('basis').optional(),
query('none_zero').optional(),
query('none_zero').optional().isBoolean().toBoolean(),
],
async handler(req, res) {
const validationErrors = validationResult(req);
@@ -462,6 +462,7 @@ export default {
const trial = journalEntries.getTrialBalance(account.id);
return {
account_id: account.id,
name: account.name,
code: account.code,
accountNormal: account.type.normal,
credit: balanceFormatter(trial.credit),
@@ -471,7 +472,7 @@ export default {
});
return res.status(200).send({
query: { ...filter },
items: [...items],
accounts: [...items],
});
},
},