fix: AR aging summary report.

This commit is contained in:
a.bouhuolia
2021-02-21 18:50:47 +02:00
parent 1aaea21f6e
commit 6e6103ca99
17 changed files with 252 additions and 272 deletions

View File

@@ -1,25 +1,19 @@
import React, { useEffect, useState, useCallback } from 'react'; import React, { useState, useCallback } from 'react';
import { useIntl } from 'react-intl';
import { queryCache, useQuery } from 'react-query';
import moment from 'moment'; import moment from 'moment';
import 'style/pages/FinancialStatements/ARAgingSummary.scss';
import { FinancialStatement } from 'components'; import { FinancialStatement } from 'components';
import DashboardInsider from 'components/Dashboard/DashboardInsider';
import ARAgingSummaryActionsBar from './ARAgingSummaryActionsBar';
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
import ARAgingSummaryHeader from './ARAgingSummaryHeader'; import ARAgingSummaryHeader from './ARAgingSummaryHeader';
import ReceivableAgingSummaryTable from './ARAgingSummaryTable'; import ARAgingSummaryActionsBar from './ARAgingSummaryActionsBar';
import ARAgingSummaryTable from './ARAgingSummaryTable';
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
import { ARAgingSummaryProvider } from './ARAgingSummaryProvider';
import withSettings from 'containers/Settings/withSettings'; import withSettings from 'containers/Settings/withSettings';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withARAgingSummaryActions from './withARAgingSummaryActions';
import withARAgingSummary from './withARAgingSummary';
import { compose } from 'utils'; import { compose } from 'utils';
import { transfromFilterFormToQuery } from './common';
import 'style/pages/FinancialStatements/ARAgingSummary.scss';
/** /**
* AR aging summary report. * AR aging summary report.
@@ -27,115 +21,55 @@ import 'style/pages/FinancialStatements/ARAgingSummary.scss';
function ReceivableAgingSummarySheet({ function ReceivableAgingSummarySheet({
// #withSettings // #withSettings
organizationName, organizationName,
// #withDashboardActions
changePageTitle,
setDashboardBackLink,
setSidebarShrink,
// #withARAgingSummaryActions
requestReceivableAgingSummary,
refreshARAgingSummary,
toggleFilterARAgingSummary,
// #withARAgingSummary
ARAgingSummaryRefresh,
}) { }) {
const { formatMessage } = useIntl(); const [filter, setFilter] = useState({
const [query, setQuery] = useState({
asDate: moment().endOf('day').format('YYYY-MM-DD'), asDate: moment().endOf('day').format('YYYY-MM-DD'),
agingBeforeDays: 30, agingDaysBefore: 30,
agingPeriods: 3, agingPeriods: 3,
}); });
useEffect(() => { // Handle filter submit.
changePageTitle(formatMessage({ id: 'receivable_aging_summary' }));
}, [changePageTitle, formatMessage]);
useEffect(() => {
if (ARAgingSummaryRefresh) {
queryCache.invalidateQueries('receivable-aging-summary');
refreshARAgingSummary(false);
}
}, [ARAgingSummaryRefresh, refreshARAgingSummary]);
useEffect(() => {
setSidebarShrink()
// Show the back link on dashboard topbar.
setDashboardBackLink(true);
return () => {
// Hide the back link on dashboard topbar.
setDashboardBackLink(false);
};
}, [setDashboardBackLink,setSidebarShrink]);
// Handle fetching receivable aging summary report.
const fetchARAgingSummarySheet = useQuery(
['receivable-aging-summary', query],
(key, q) =>
requestReceivableAgingSummary({
...transfromFilterFormToQuery(q),
}),
{ manual: true },
);
// Handle fetch the data of receivable aging summary sheet.
const handleFetchData = useCallback((...args) => {}, []);
const handleFilterSubmit = useCallback( const handleFilterSubmit = useCallback(
(filter) => { (filter) => {
const _filter = { const _filter = {
...filter, ...filter,
asDate: moment(filter.asDate).format('YYYY-MM-DD'), asDate: moment(filter.asDate).format('YYYY-MM-DD'),
}; };
setQuery(_filter); setFilter(_filter);
refreshARAgingSummary(true);
toggleFilterARAgingSummary(false);
}, },
[refreshARAgingSummary, toggleFilterARAgingSummary], [],
); );
// Handle number format submit.
const handleNumberFormatSubmit = (numberFormat) => { const handleNumberFormatSubmit = (numberFormat) => {
setQuery({ setFilter({ ...filter, numberFormat });
...query,
numberFormat
});
refreshARAgingSummary(true);
}; };
return ( return (
<DashboardInsider> <ARAgingSummaryProvider filter={filter}>
<ARAgingSummaryActionsBar <ARAgingSummaryActionsBar
numberFormat={query.numberFormat} numberFormat={filter.numberFormat}
onNumberFormatSubmit={handleNumberFormatSubmit}/> onNumberFormatSubmit={handleNumberFormatSubmit}/>
<DashboardPageContent> <DashboardPageContent>
<FinancialStatement> <FinancialStatement>
<ARAgingSummaryHeader <ARAgingSummaryHeader
pageFilter={query} pageFilter={filter}
onSubmitFilter={handleFilterSubmit} onSubmitFilter={handleFilterSubmit}
/> />
<div class="financial-statement__body"> <div class="financial-statement__body">
<ReceivableAgingSummaryTable <ARAgingSummaryTable
organizationName={organizationName} organizationName={organizationName}
receivableAgingSummaryQuery={query}
onFetchData={handleFetchData}
/> />
</div> </div>
</FinancialStatement> </FinancialStatement>
</DashboardPageContent> </DashboardPageContent>
</DashboardInsider> </ARAgingSummaryProvider>
); );
} }
export default compose( export default compose(
withDashboardActions,
withARAgingSummaryActions,
withSettings(({ organizationSettings }) => ({ withSettings(({ organizationSettings }) => ({
organizationName: organizationSettings.name, organizationName: organizationSettings.name,
})), })),
withARAgingSummary(({ ARAgingSummaryRefresh }) => ({
ARAgingSummaryRefresh: ARAgingSummaryRefresh,
})),
)(ReceivableAgingSummarySheet); )(ReceivableAgingSummarySheet);

View File

@@ -15,34 +15,34 @@ import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar';
import Icon from 'components/Icon'; import Icon from 'components/Icon';
import NumberFormatDropdown from 'components/NumberFormatDropdown'; import NumberFormatDropdown from 'components/NumberFormatDropdown';
import withARAgingSummary from './withARAgingSummary'; import { useARAgingSummaryContext } from './ARAgingSummaryProvider';
import withARAgingSummaryActions from './withARAgingSummaryActions'; import withARAgingSummaryActions from './withARAgingSummaryActions';
import { compose } from 'utils'; import { compose } from 'utils';
import { safeInvoke } from '@blueprintjs/core/lib/esm/common/utils'; import { safeInvoke } from '@blueprintjs/core/lib/esm/common/utils';
/** /**
* AR Aging summary sheet - Actions bar. * A/R Aging summary sheet - Actions bar.
*/ */
function ARAgingSummaryActionsBar({ function ARAgingSummaryActionsBar({
// #withReceivableAging // #withReceivableAging
receivableAgingFilter, receivableAgingFilter,
ARAgingSummaryLoading,
// #withReceivableAgingActions // #withReceivableAgingActions
toggleFilterARAgingSummary, toggleFilterARAgingSummary,
refreshARAgingSummary,
// #ownProps // #ownProps
numberFormat, numberFormat,
onNumberFormatSubmit, onNumberFormatSubmit,
}) { }) {
const { isARAgingFetching, refetch } = useARAgingSummaryContext();
const handleFilterToggleClick = () => { const handleFilterToggleClick = () => {
toggleFilterARAgingSummary(); toggleFilterARAgingSummary();
}; };
// Handles re-calculate report button. // Handles re-calculate report button.
const handleRecalcReport = () => { const handleRecalcReport = () => {
refreshARAgingSummary(true); refetch();
}; };
// Handle number format submit. // Handle number format submit.
const handleNumberFormatSubmit = (numberFormat) => { const handleNumberFormatSubmit = (numberFormat) => {
@@ -80,7 +80,7 @@ function ARAgingSummaryActionsBar({
<NumberFormatDropdown <NumberFormatDropdown
numberFormat={numberFormat} numberFormat={numberFormat}
onSubmit={handleNumberFormatSubmit} onSubmit={handleNumberFormatSubmit}
submitDisabled={ARAgingSummaryLoading} submitDisabled={isARAgingFetching}
/> />
} }
minimal={true} minimal={true}
@@ -118,7 +118,4 @@ function ARAgingSummaryActionsBar({
export default compose( export default compose(
withARAgingSummaryActions, withARAgingSummaryActions,
withARAgingSummary(({ receivableAgingSummaryLoading }) => ({
ARAgingSummaryLoading: receivableAgingSummaryLoading,
})),
)(ARAgingSummaryActionsBar); )(ARAgingSummaryActionsBar);

View File

@@ -17,24 +17,21 @@ import { compose } from 'utils';
* AR Aging Summary Report - Drawer Header. * AR Aging Summary Report - Drawer Header.
*/ */
function ARAgingSummaryHeader({ function ARAgingSummaryHeader({
// #ownProps
pageFilter, pageFilter,
onSubmitFilter, onSubmitFilter,
receivableAgingFilter, receivableAgingFilter,
// #withReceivableAgingSummary
receivableAgingRefresh,
// #withReceivableAgingSummaryActions // #withReceivableAgingSummaryActions
refreshReceivableAgingSummary,
toggleFilterARAgingSummary, toggleFilterARAgingSummary,
}) { }) {
const validationSchema = Yup.object().shape({ const validationSchema = Yup.object().shape({
asDate: Yup.date().required().label('asDate'), asDate: Yup.date().required().label('asDate'),
agingBeforeDays: Yup.number() agingDaysBefore: Yup.number()
.required() .required()
.integer() .integer()
.positive() .positive()
.label('agingBeforeDays'), .label('agingDaysBefore'),
agingPeriods: Yup.number() agingPeriods: Yup.number()
.required() .required()
.integer() .integer()
@@ -44,12 +41,13 @@ function ARAgingSummaryHeader({
// Initial values. // Initial values.
const initialValues = { const initialValues = {
asDate: moment(pageFilter.asDate).toDate(), asDate: moment(pageFilter.asDate).toDate(),
agingBeforeDays: 30, agingDaysBefore: 30,
agingPeriods: 3, agingPeriods: 3,
}; };
// Handle form submit. // Handle form submit.
const handleSubmit = (values, { setSubmitting }) => { const handleSubmit = (values, { setSubmitting }) => {
onSubmitFilter(values); onSubmitFilter(values);
toggleFilterARAgingSummary();
setSubmitting(false); setSubmitting(false);
}; };
// Handle cancel button click. // Handle cancel button click.
@@ -89,10 +87,7 @@ function ARAgingSummaryHeader({
export default compose( export default compose(
withARAgingSummaryActions, withARAgingSummaryActions,
withARAgingSummary( withARAgingSummary(({ receivableAgingSummaryFilter }) => ({
({ receivableAgingSummaryFilter, receivableAgingSummaryRefresh }) => ({ receivableAgingFilter: receivableAgingSummaryFilter,
receivableAgingFilter: receivableAgingSummaryFilter, })),
receivableAgingRefresh: receivableAgingSummaryRefresh,
}),
),
)(ARAgingSummaryHeader); )(ARAgingSummaryHeader);

View File

@@ -12,17 +12,16 @@ import { FormattedMessage as T } from 'react-intl';
import classNames from 'classnames'; import classNames from 'classnames';
import { CustomersMultiSelect, Row, Col, FieldHint } from 'components'; import { CustomersMultiSelect, Row, Col, FieldHint } from 'components';
import { momentFormatter } from 'utils'; import { momentFormatter } from 'utils';
// import withCustomers from 'containers/Customers/withCustomers';
import { compose } from 'redux'; import { useARAgingSummaryContext } from './ARAgingSummaryProvider';
/** /**
* AR Aging Summary - Drawer Header - General Fields. * AR Aging Summary - Drawer Header - General Fields.
*/ */
function ARAgingSummaryHeaderGeneral({ export default function ARAgingSummaryHeaderGeneral() {
// #withCustomers // AR Aging summary context.
customers, const { customers } = useARAgingSummaryContext();
}) {
return ( return (
<div> <div>
<Row> <Row>
@@ -53,7 +52,7 @@ function ARAgingSummaryHeaderGeneral({
<Row> <Row>
<Col xs={5}> <Col xs={5}>
<FastField name={'agingBeforeDays'}> <FastField name={'agingDaysBefore'}>
{({ field, meta: { error, touched } }) => ( {({ field, meta: { error, touched } }) => (
<FormGroup <FormGroup
label={<T id={'aging_before_days'} />} label={<T id={'aging_before_days'} />}
@@ -104,9 +103,4 @@ function ARAgingSummaryHeaderGeneral({
</Row> </Row>
</div> </div>
); );
} }
export default compose(
// withCustomers(({ customers }) => ({
// customers,
// })),
)(ARAgingSummaryHeaderGeneral);

View File

@@ -0,0 +1,47 @@
import React, { useMemo, createContext, useContext } from 'react';
import DashboardInsider from 'components/Dashboard/DashboardInsider';
import { useARAgingSummaryReport, useCustomers } from 'hooks/query';
import { transformFilterFormToQuery } from '../common';
const ARAgingSummaryContext = createContext();
/**
* A/R aging summary provider.
*/
function ARAgingSummaryProvider({ filter, ...props }) {
// Transformes the filter from to the Url query.
const query = useMemo(() => transformFilterFormToQuery(filter), [filter]);
const {
data: ARAgingSummary,
isLoading: isARAgingLoading,
isFetching: isARAgingFetching,
refetch,
} = useARAgingSummaryReport(query);
// Retrieve the customers list.
const {
data: { customers },
isFetching: isCustomersFetching,
} = useCustomers();
const provider = {
ARAgingSummary,
customers,
isARAgingLoading,
isARAgingFetching,
isCustomersFetching,
refetch,
};
return (
<DashboardInsider name={'AR-Aging-Summary'}>
<ARAgingSummaryContext.Provider value={provider} {...props} />
</DashboardInsider>
);
}
const useARAgingSummaryContext = () => useContext(ARAgingSummaryContext);
export { ARAgingSummaryProvider, useARAgingSummaryContext };

View File

@@ -1,72 +1,25 @@
import React, { useMemo, useCallback } from 'react'; import React, { useCallback } from 'react';
import { FormattedMessage as T, useIntl } from 'react-intl'; import { useIntl } from 'react-intl';
import DataTable from 'components/DataTable'; import DataTable from 'components/DataTable';
import FinancialSheet from 'components/FinancialSheet'; import FinancialSheet from 'components/FinancialSheet';
import withARAgingSummary from './withARAgingSummary'; import { useARAgingSummaryContext } from './ARAgingSummaryProvider';
import { useARAgingSummaryColumns } from './components';
import { compose, getColumnWidth } from 'utils';
/** /**
* AR aging summary table sheet. * AR aging summary table sheet.
*/ */
function ReceivableAgingSummaryTable({ export default function ReceivableAgingSummaryTable({
// #withReceivableAgingSummary
receivableAgingRows,
receivableAgingLoading,
receivableAgingColumns,
// #ownProps // #ownProps
onFetchData,
organizationName, organizationName,
}) { }) {
const { formatMessage } = useIntl(); const { formatMessage } = useIntl();
const agingColumns = useMemo(() => { // AR aging summary report context.
return receivableAgingColumns.map((agingColumn) => { const { ARAgingSummary, isARAgingFetching } = useARAgingSummaryContext();
return `${agingColumn.before_days} - ${
agingColumn.to_days || 'And Over'
}`;
});
}, [receivableAgingColumns]);
const columns = useMemo( // AR aging summary columns.
() => [ const columns = useARAgingSummaryColumns();
{
Header: <T id={'customer_name'} />,
accessor: 'name',
className: 'customer_name',
sticky: 'left',
width: 240,
textOverview: true,
},
{
Header: <T id={'current'} />,
accessor: 'current',
className: 'current',
width: getColumnWidth(receivableAgingRows, `current`, {
minWidth: 120,
}),
},
...agingColumns.map((agingColumn, index) => ({
Header: agingColumn,
accessor: `aging-${index }`,
width: getColumnWidth(receivableAgingRows, `aging-${index }`, {
minWidth: 120,
}),
})),
{
Header: (<T id={'total'} />),
id: 'total',
accessor: 'total',
className: 'total',
width: getColumnWidth(receivableAgingRows, 'total', {
minWidth: 120,
}),
},
],
[receivableAgingRows, agingColumns],
);
const rowClassNames = (row) => [`row-type--${row.original.rowType}`]; const rowClassNames = (row) => [`row-type--${row.original.rowType}`];
@@ -80,12 +33,12 @@ function ReceivableAgingSummaryTable({
name={'receivable-aging-summary'} name={'receivable-aging-summary'}
sheetType={formatMessage({ id: 'receivable_aging_summary' })} sheetType={formatMessage({ id: 'receivable_aging_summary' })}
asDate={new Date()} asDate={new Date()}
loading={receivableAgingLoading} loading={isARAgingFetching}
> >
<DataTable <DataTable
className="bigcapital-datatable--financial-report" className="bigcapital-datatable--financial-report"
columns={columns} columns={columns}
data={receivableAgingRows} data={ARAgingSummary.tableRows}
rowClassNames={rowClassNames} rowClassNames={rowClassNames}
onFetchData={handleFetchData} onFetchData={handleFetchData}
noInitialFetch={true} noInitialFetch={true}
@@ -94,17 +47,3 @@ function ReceivableAgingSummaryTable({
</FinancialSheet> </FinancialSheet>
); );
} }
export default compose(
withARAgingSummary(
({
receivableAgingSummaryLoading,
receivableAgingSummaryColumns,
receivableAgingSummaryRows,
}) => ({
receivableAgingLoading: receivableAgingSummaryLoading,
receivableAgingColumns: receivableAgingSummaryColumns,
receivableAgingRows: receivableAgingSummaryRows,
}),
),
)(ReceivableAgingSummaryTable);

View File

@@ -0,0 +1,58 @@
import React from 'react';
import { useARAgingSummaryContext } from './ARAgingSummaryProvider';
import { getColumnWidth } from 'utils';
import { FormattedMessage as T } from 'react-intl';
/**
* Retrieve AR aging summary columns.
*/
export const useARAgingSummaryColumns = () => {
const {
ARAgingSummary: { tableRows, columns },
} = useARAgingSummaryContext();
const agingColumns = React.useMemo(() => {
return columns.map(
(agingColumn) =>
`${agingColumn.before_days} - ${agingColumn.to_days || 'And Over'}`,
);
}, [columns]);
return React.useMemo(
() => [
{
Header: <T id={'customer_name'} />,
accessor: 'name',
className: 'customer_name',
sticky: 'left',
width: 240,
textOverview: true,
},
{
Header: <T id={'current'} />,
accessor: 'current',
className: 'current',
width: getColumnWidth(tableRows, `current`, {
minWidth: 120,
}),
},
...agingColumns.map((agingColumn, index) => ({
Header: agingColumn,
accessor: `aging-${index}`,
width: getColumnWidth(tableRows, `aging-${index}`, {
minWidth: 120,
}),
})),
{
Header: <T id={'total'} />,
id: 'total',
accessor: 'total',
className: 'total',
width: getColumnWidth(tableRows, 'total', {
minWidth: 120,
}),
},
],
[tableRows, agingColumns],
);
};

View File

@@ -40,6 +40,7 @@ function BalanceSheet({
setFilter({ ..._filter }); setFilter({ ..._filter });
}; };
// Hnadle number format submit.
const handleNumberFormatSubmit = (values) => { const handleNumberFormatSubmit = (values) => {
setFilter({ setFilter({
...filter, ...filter,
@@ -48,7 +49,7 @@ function BalanceSheet({
}; };
return ( return (
<BalanceSheetProvider query={filter}> <BalanceSheetProvider filter={filter}>
<BalanceSheetActionsBar <BalanceSheetActionsBar
numberFormat={filter.numberFormat} numberFormat={filter.numberFormat}
onNumberFormatSubmit={handleNumberFormatSubmit} onNumberFormatSubmit={handleNumberFormatSubmit}

View File

@@ -5,15 +5,20 @@ import { transformFilterFormToQuery } from '../common';
const BalanceSheetContext = createContext(); const BalanceSheetContext = createContext();
function BalanceSheetProvider({ query, ...props }) { function BalanceSheetProvider({ filter, ...props }) {
const { data: balanceSheet, isFetching, refetch } = useBalanceSheet({ // Transformes the given filter to query.
...transformFilterFormToQuery(query), const query = React.useMemo(() => transformFilterFormToQuery(filter), [filter]);
});
// Fetches the balance sheet report.
const { data: balanceSheet, isFetching, refetch } = useBalanceSheet(query);
const provider = { const provider = {
balanceSheet, balanceSheet,
isLoading: isFetching, isLoading: isFetching,
refetchBalanceSheet: refetch refetchBalanceSheet: refetch,
query,
filter,
}; };
return ( return (
<DashboardInsider name={'balance-sheet'}> <DashboardInsider name={'balance-sheet'}>

View File

@@ -1,6 +1,5 @@
import React, { useEffect, useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import moment from 'moment'; import moment from 'moment';
import { useIntl } from 'react-intl';
import 'style/pages/FinancialStatements/GeneralLedger.scss'; import 'style/pages/FinancialStatements/GeneralLedger.scss';
@@ -12,28 +11,21 @@ import GeneralLedgerActionsBar from './GeneralLedgerActionsBar';
import { GeneralLedgerProvider } from './GeneralLedgerProvider'; import { GeneralLedgerProvider } from './GeneralLedgerProvider';
import withGeneralLedgerActions from './withGeneralLedgerActions'; import withGeneralLedgerActions from './withGeneralLedgerActions';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withSettings from 'containers/Settings/withSettings'; import withSettings from 'containers/Settings/withSettings';
import { compose } from 'utils';
import { transformFilterFormToQuery } from 'containers/FinancialStatements/common'; import { transformFilterFormToQuery } from 'containers/FinancialStatements/common';
import { compose } from 'utils';
/** /**
* General Ledger (GL) sheet. * General Ledger (GL) sheet.
*/ */
function GeneralLedger({ function GeneralLedger({
// #withDashboardActions
changePageTitle,
setDashboardBackLink,
// #withGeneralLedgerActions // #withGeneralLedgerActions
refreshGeneralLedgerSheet, refreshGeneralLedgerSheet,
// #withSettings // #withSettings
organizationName, organizationName,
}) { }) {
const { formatMessage } = useIntl();
const [filter, setFilter] = useState({ const [filter, setFilter] = useState({
fromDate: moment().startOf('year').format('YYYY-MM-DD'), fromDate: moment().startOf('year').format('YYYY-MM-DD'),
toDate: moment().endOf('year').format('YYYY-MM-DD'), toDate: moment().endOf('year').format('YYYY-MM-DD'),
@@ -41,21 +33,6 @@ function GeneralLedger({
accountsFilter: 'with-transactions', accountsFilter: 'with-transactions',
}); });
// Change page title of the dashboard.
useEffect(() => {
changePageTitle(formatMessage({ id: 'general_ledger' }));
}, [changePageTitle, formatMessage]);
useEffect(() => {
// Show the back link on dashboard topbar.
setDashboardBackLink(true);
return () => {
// Hide the back link on dashboard topbar.
setDashboardBackLink(false);
};
});
// Handle financial statement filter change. // Handle financial statement filter change.
const handleFilterSubmit = useCallback( const handleFilterSubmit = useCallback(
(filter) => { (filter) => {
@@ -71,7 +48,7 @@ function GeneralLedger({
); );
return ( return (
<GeneralLedgerProvider query={filter}> <GeneralLedgerProvider query={transformFilterFormToQuery(filter)}>
<GeneralLedgerActionsBar /> <GeneralLedgerActionsBar />
<DashboardPageContent> <DashboardPageContent>
@@ -95,7 +72,6 @@ function GeneralLedger({
export default compose( export default compose(
withGeneralLedgerActions, withGeneralLedgerActions,
withDashboardActions,
withSettings(({ organizationSettings }) => ({ withSettings(({ organizationSettings }) => ({
organizationName: organizationSettings.name, organizationName: organizationSettings.name,
})), })),

View File

@@ -5,7 +5,6 @@ import {
} from '@blueprintjs/core'; } from '@blueprintjs/core';
import { FormattedMessage as T } from 'react-intl'; import { FormattedMessage as T } from 'react-intl';
import classNames from 'classnames'; import classNames from 'classnames';
import { compose } from 'redux';
import { AccountsMultiSelect, Row, Col } from 'components'; import { AccountsMultiSelect, Row, Col } from 'components';
@@ -13,17 +12,15 @@ import FinancialStatementDateRange from 'containers/FinancialStatements/Financia
import RadiosAccountingBasis from '../RadiosAccountingBasis'; import RadiosAccountingBasis from '../RadiosAccountingBasis';
import FinancialAccountsFilter from '../FinancialAccountsFilter'; import FinancialAccountsFilter from '../FinancialAccountsFilter';
import withAccounts from 'containers/Accounts/withAccounts';
import { filterAccountsOptions } from './common'; import { filterAccountsOptions } from './common';
import { useGeneralLedgerContext } from './GeneralLedgerProvider'
/** /**
* General ledger (GL) - Header - General panel. * General ledger (GL) - Header - General panel.
*/ */
function GeneralLedgerHeaderGeneralPane({ export default function GeneralLedgerHeaderGeneralPane() {
// #withAccounts const { accounts } = useGeneralLedgerContext();
accountsList,
}) {
return ( return (
<div> <div>
<FinancialStatementDateRange /> <FinancialStatementDateRange />
@@ -37,7 +34,7 @@ function GeneralLedgerHeaderGeneralPane({
label={<T id={'specific_accounts'} />} label={<T id={'specific_accounts'} />}
className={classNames('form-group--select-list', Classes.FILL)} className={classNames('form-group--select-list', Classes.FILL)}
> >
<AccountsMultiSelect accounts={accountsList} /> <AccountsMultiSelect accounts={accounts} />
</FormGroup> </FormGroup>
</Col> </Col>
</Row> </Row>
@@ -45,8 +42,4 @@ function GeneralLedgerHeaderGeneralPane({
<RadiosAccountingBasis key={'basis'} /> <RadiosAccountingBasis key={'basis'} />
</div> </div>
); );
} }
export default compose(withAccounts(({ accountsList }) => ({ accountsList })))(
GeneralLedgerHeaderGeneralPane,
);

View File

@@ -1,14 +1,14 @@
import React, { createContext, useContext } from 'react'; import React, { createContext, useContext } from 'react';
import DashboardInsider from 'components/Dashboard/DashboardInsider'; import DashboardInsider from 'components/Dashboard/DashboardInsider';
import { useGeneralLedgerSheet, useAccounts } from 'hooks/query'; import { useGeneralLedgerSheet, useAccounts } from 'hooks/query';
import { transformFilterFormToQuery } from '../common';
const GeneralLedgerContext = createContext(); const GeneralLedgerContext = createContext();
/**
* General ledger provider.
*/
function GeneralLedgerProvider({ query, ...props }) { function GeneralLedgerProvider({ query, ...props }) {
const { data: generalLedger, isFetching, refetch } = useGeneralLedgerSheet({ const { data: generalLedger, isFetching, refetch } = useGeneralLedgerSheet(query);
...transformFilterFormToQuery(query),
});
// Accounts list. // Accounts list.
const { data: accounts, isFetching: isAccountsLoading } = useAccounts(); const { data: accounts, isFetching: isAccountsLoading } = useAccounts();

View File

@@ -1,6 +1,5 @@
import React, { useEffect, useCallback, useState } from 'react'; import React, { useCallback, useState } from 'react';
import moment from 'moment'; import moment from 'moment';
import { useIntl } from 'react-intl';
import 'style/pages/FinancialStatements/TrialBalanceSheet.scss'; import 'style/pages/FinancialStatements/TrialBalanceSheet.scss';
@@ -10,7 +9,6 @@ import TrialBalanceSheetHeader from './TrialBalanceSheetHeader';
import TrialBalanceSheetTable from './TrialBalanceSheetTable'; import TrialBalanceSheetTable from './TrialBalanceSheetTable';
import DashboardPageContent from 'components/Dashboard/DashboardPageContent'; import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
import withDashboardActions from 'containers/Dashboard/withDashboardActions';
import withTrialBalanceActions from './withTrialBalanceActions'; import withTrialBalanceActions from './withTrialBalanceActions';
import withSettings from 'containers/Settings/withSettings'; import withSettings from 'containers/Settings/withSettings';
import withTrialBalance from './withTrialBalance'; import withTrialBalance from './withTrialBalance';
@@ -21,16 +19,9 @@ import { compose } from 'utils';
* Trial balance sheet. * Trial balance sheet.
*/ */
function TrialBalanceSheet({ function TrialBalanceSheet({
// #withDashboardActions
changePageTitle,
setDashboardBackLink,
setSidebarShrink,
// #withPreferences // #withPreferences
organizationName, organizationName,
}) { }) {
const { formatMessage } = useIntl();
const [filter, setFilter] = useState({ const [filter, setFilter] = useState({
fromDate: moment().startOf('year').format('YYYY-MM-DD'), fromDate: moment().startOf('year').format('YYYY-MM-DD'),
toDate: moment().endOf('year').format('YYYY-MM-DD'), toDate: moment().endOf('year').format('YYYY-MM-DD'),
@@ -38,22 +29,6 @@ function TrialBalanceSheet({
accountsFilter: 'all-accounts', accountsFilter: 'all-accounts',
}); });
// Change page title of the dashboard.
useEffect(() => {
changePageTitle(formatMessage({ id: 'trial_balance_sheet' }));
}, [changePageTitle, formatMessage]);
useEffect(() => {
setSidebarShrink();
// Show the back link on dashboard topbar.
setDashboardBackLink(true);
return () => {
// Hide the back link on dashboard topbar.
setDashboardBackLink(false);
};
}, [setDashboardBackLink, setSidebarShrink]);
// Handle filter form submit. // Handle filter form submit.
const handleFilterSubmit = useCallback( const handleFilterSubmit = useCallback(
(filter) => { (filter) => {
@@ -97,7 +72,6 @@ function TrialBalanceSheet({
} }
export default compose( export default compose(
withDashboardActions,
withTrialBalanceActions, withTrialBalanceActions,
withTrialBalance(({ trialBalanceQuery }) => ({ withTrialBalance(({ trialBalanceQuery }) => ({
trialBalanceQuery, trialBalanceQuery,

View File

@@ -1,5 +1,5 @@
import { omit } from 'lodash'; import { omit } from 'lodash';
import { transformToCamelCase, flatObject } from 'utils'; import { transfromToSnakeCase, flatObject } from 'utils';
import { formatMessage } from 'services/intl'; import { formatMessage } from 'services/intl';
export const displayColumnsByOptions = [ export const displayColumnsByOptions = [
@@ -53,7 +53,7 @@ export const transformDisplayColumnsType = (form) => {
}; };
export const transformFilterFormToQuery = (form) => { export const transformFilterFormToQuery = (form) => {
const transformed = transformToCamelCase({ const transformed = transfromToSnakeCase({
...omit(form, ['accountsFilter']), ...omit(form, ['accountsFilter']),
...transformDisplayColumnsType(form), ...transformDisplayColumnsType(form),
noneZero: form.accountsFilter === 'without-zero-balance', noneZero: form.accountsFilter === 'without-zero-balance',

View File

@@ -226,3 +226,38 @@ export const generalLedgerTableRowsReducer = (accounts) => {
}) })
.value(); .value();
}; };
export const ARAgingSummaryTableRowsMapper = (sheet, total) => {
const rows = [];
const mapAging = (agingPeriods) => {
return agingPeriods.reduce((acc, aging, index) => {
acc[`aging-${index}`] = aging.total.formatted_amount;
return acc;
}, {});
};
sheet.customers.forEach((customer) => {
const agingRow = mapAging(customer.aging);
rows.push({
rowType: 'customer',
name: customer.customer_name,
...agingRow,
current: customer.current.formatted_amount,
total: customer.total.formatted_amount,
});
});
if (rows.length <= 0) {
return [];
}
return [
...rows,
{
name: '',
rowType: 'total',
current: sheet.total.current.formatted_amount,
...mapAging(sheet.total.aging),
total: sheet.total.total.formatted_amount,
},
];
};

View File

@@ -6,6 +6,7 @@ import {
profitLossSheetReducer, profitLossSheetReducer,
generalLedgerTableRowsReducer, generalLedgerTableRowsReducer,
journalTableRowsReducer, journalTableRowsReducer,
ARAgingSummaryTableRowsMapper
} from 'containers/FinancialStatements/reducers'; } from 'containers/FinancialStatements/reducers';
import useApiRequest from '../useRequest'; import useApiRequest from '../useRequest';
@@ -175,6 +176,29 @@ export function useARAgingSummaryReport(query, props) {
apiRequest.get('/financial_statements/receivable_aging_summary', { apiRequest.get('/financial_statements/receivable_aging_summary', {
params: query, params: query,
}), }),
props, {
select: (res) => ({
columns: res.data.columns,
data: res.data.data,
query: res.data.query,
tableRows: ARAgingSummaryTableRowsMapper({
customers: res.data.data.customers,
total: res.data.data.total,
columns: res.data.columns,
}),
}),
initialData: {
data: {
data: {
customers: [],
total: {},
},
columns: [],
tableRows: []
}
},
initialDataUpdatedAt: 0,
...props
},
); );
} }

View File

@@ -110,6 +110,9 @@ export default [
), ),
breadcrumb: 'General Ledger', breadcrumb: 'General Ledger',
hotkey: 'shift+4', hotkey: 'shift+4',
pageTitle: formatMessage({ id: 'general_ledger' }),
backLink: true,
sidebarShrink: true
}, },
{ {
path: `/financial-reports/balance-sheet`, path: `/financial-reports/balance-sheet`,
@@ -131,6 +134,8 @@ export default [
), ),
breadcrumb: 'Trial Balance Sheet', breadcrumb: 'Trial Balance Sheet',
hotkey: 'shift+5', hotkey: 'shift+5',
pageTitle: formatMessage({ id: 'trial_balance_sheet' }),
backLink: true,
}, },
{ {
path: `/financial-reports/profit-loss-sheet`, path: `/financial-reports/profit-loss-sheet`,
@@ -146,6 +151,9 @@ export default [
import('containers/FinancialStatements/ARAgingSummary/ARAgingSummary'), import('containers/FinancialStatements/ARAgingSummary/ARAgingSummary'),
), ),
breadcrumb: 'Receivable Aging Summary', breadcrumb: 'Receivable Aging Summary',
pageTitle: formatMessage({ id: 'receivable_aging_summary' }),
backLink: true,
sidebarShrink: true,
}, },
{ {
path: `/financial-reports/journal-sheet`, path: `/financial-reports/journal-sheet`,