From 201d789cb8b2aa6a6834345a40fbb87e52927b4c Mon Sep 17 00:00:00 2001 From: elforjani3 Date: Sun, 24 Jan 2021 22:58:47 +0200 Subject: [PATCH 1/7] feat: APAgingSummary. --- client/src/config/sidebarMenu.js | 6 +- .../APAgingSummary/APAgingSummary.js | 128 +++++++ .../APAgingSummaryActionsBar.js | 123 ++++++ .../APAgingSummary/APAgingSummaryHeader.js | 90 +++++ .../APAgingSummaryHeaderGeneral.js | 77 ++++ .../APAgingSummary/APAgingSummaryTable.js | 103 +++++ .../APAgingSummary/common.js | 5 + .../APAgingSummary/withAPAgingSummary.js | 35 ++ .../withAPAgingSummaryActions.js | 18 + .../ARAgingSummary/ARAgingSummary.js | 7 +- .../ARAgingSummaryActionsBar.js | 3 +- client/src/lang/en/index.js | 3 +- client/src/routes/dashboard.js | 8 + .../financialStatements.actions.js | 353 +++++++++++------- .../financialStatements.mappers.js | 45 ++- .../financialStatements.reducer.js | 35 +- .../financialStatements.types.js | 8 +- 17 files changed, 893 insertions(+), 154 deletions(-) create mode 100644 client/src/containers/FinancialStatements/APAgingSummary/APAgingSummary.js create mode 100644 client/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryActionsBar.js create mode 100644 client/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryHeader.js create mode 100644 client/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryHeaderGeneral.js create mode 100644 client/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryTable.js create mode 100644 client/src/containers/FinancialStatements/APAgingSummary/common.js create mode 100644 client/src/containers/FinancialStatements/APAgingSummary/withAPAgingSummary.js create mode 100644 client/src/containers/FinancialStatements/APAgingSummary/withAPAgingSummaryActions.js diff --git a/client/src/config/sidebarMenu.js b/client/src/config/sidebarMenu.js index 41829981c..c97d0020a 100644 --- a/client/src/config/sidebarMenu.js +++ b/client/src/config/sidebarMenu.js @@ -1,4 +1,4 @@ - import React from 'react'; +import React from 'react'; import { FormattedMessage as T } from 'react-intl'; export default [ @@ -167,11 +167,11 @@ export default [ href: '/financial-reports/profit-loss-sheet', }, { - text: 'Receivable Aging Summary', + text: , href: '/financial-reports/receivable-aging-summary', }, { - text: 'Payable Aging Summary', + text: , href: '/financial-reports/payable-aging-summary', }, ], diff --git a/client/src/containers/FinancialStatements/APAgingSummary/APAgingSummary.js b/client/src/containers/FinancialStatements/APAgingSummary/APAgingSummary.js new file mode 100644 index 000000000..79b6e7025 --- /dev/null +++ b/client/src/containers/FinancialStatements/APAgingSummary/APAgingSummary.js @@ -0,0 +1,128 @@ +import React, { useEffect, useState, useCallback } from 'react'; +import { useIntl } from 'react-intl'; +import { queryCache, useQuery } from 'react-query'; +import moment from 'moment'; + +import { FinancialStatement } from 'components'; + +import DashboardInsider from 'components/Dashboard/DashboardInsider'; +import DashboardPageContent from 'components/Dashboard/DashboardPageContent'; + +import APAgingSummaryActionsBar from './APAgingSummaryActionsBar'; +import APAgingSummaryHeader from './APAgingSummaryHeader'; +import APAgingSummaryTable from './APAgingSummaryTable'; + +import withSettings from 'containers/Settings/withSettings'; +import withDashboardActions from 'containers/Dashboard/withDashboardActions'; +import withAPAgingSummaryActions from './withAPAgingSummaryActions'; +import withAPAgingSummary from './withAPAgingSummary'; +import { transformFilterFormToQuery } from './common'; + +import { compose } from 'utils'; + +import 'style/pages/FinancialStatements/ARAgingSummary.scss'; + +/** + * AP aging summary report. + */ +function APAgingSummary({ + // #withSettings + organizationName, + + // #withDashboardActions + changePageTitle, + setDashboardBackLink, + + // #withAPAgingSummary + APAgingSummaryRefresh, + + // #withAPAgingSummaryActions + requestPayableAgingSummary, + refreshAPAgingSummary, + toggleFilterAPAgingSummary, +}) { + const { formatMessage } = useIntl(); + + const [query, setQuery] = useState({ + asDate: moment().endOf('day').format('YYYY-MM-DD'), + agingBeforeDays: 30, + agingPeriods: 3, + }); + + // handle fetching payable aging summary report. + const fetchAPAgingSummarySheet = useQuery( + ['payable-aging-summary', query], + (key, _query) => + requestPayableAgingSummary({ + ...transformFilterFormToQuery(_query), + }), + { enable: true }, + ); + + useEffect(() => { + changePageTitle(formatMessage({ id: 'payable_aging_summary' })); + }, [changePageTitle, formatMessage]); + + useEffect(() => { + if (APAgingSummaryRefresh) { + queryCache.invalidateQueries('payable-aging-summary'); + refreshAPAgingSummary(false); + } + }, [APAgingSummaryRefresh, refreshAPAgingSummary]); + + useEffect(() => { + setDashboardBackLink(true); + return () => { + setDashboardBackLink(false); + }; + }, [setDashboardBackLink]); + + const handleFilterSubmit = (filter) => { + const _filter = { + ...filter, + asDate: moment(filter.asDate).format('YYYY-MM-DD'), + }; + setQuery(_filter); + refreshAPAgingSummary(true); + toggleFilterAPAgingSummary(false); + }; + + const handleNumberFormatSubmit = (numberFormat) => { + setQuery({ + ...query, + numberFormat, + }); + refreshAPAgingSummary(true); + }; + + return ( + + + + + +
+ +
+
+
+
+ ); +} + +export default compose( + withDashboardActions, + withAPAgingSummaryActions, + withSettings(({ organizationSettings }) => ({ + organizationName: organizationSettings.name, + })), + withAPAgingSummary(({ APAgingSummaryRefresh }) => ({ + APAgingSummaryRefresh, + })), +)(APAgingSummary); diff --git a/client/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryActionsBar.js b/client/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryActionsBar.js new file mode 100644 index 000000000..5426ab7af --- /dev/null +++ b/client/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryActionsBar.js @@ -0,0 +1,123 @@ +import React from 'react'; +import { + NavbarDivider, + NavbarGroup, + Classes, + Button, + Popover, + PopoverInteractionKind, + Position, +} from '@blueprintjs/core'; +import { safeInvoke } from '@blueprintjs/core/lib/esm/common/utils'; + +import { FormattedMessage as T } from 'react-intl'; +import classNames from 'classnames'; + +import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar'; +import { Icon } from 'components'; +import NumberFormatDropdown from 'components/NumberFormatDropdown'; + +import withAPAgingSummary from './withAPAgingSummary'; +import withARAgingSummaryActions from './withAPAgingSummaryActions'; + +import { compose } from 'utils'; + +/** + * AP Aging summary sheet - Actions bar. + */ +function APAgingSummaryActionsBar({ + //#withPayableAgingSummary + payableAgingFilter, + payableAgingLoading, + + //#withARAgingSummaryActions + toggleFilterAPAgingSummary, + refreshAPAgingSummary, + + //#ownProps + numberFormat, + onNumberFormatSubmit, +}) { + const handleFilterToggleClick = () => toggleFilterAPAgingSummary(); + + // handle recalculate report button. + const handleRecalculateReport = () => refreshAPAgingSummary(true); + + // handle number format submit. + const handleNumberFormatSubmit = (numberFormat) => + safeInvoke(onNumberFormatSubmit, numberFormat); + + return ( + + + + + + + + + ); +} + +export default compose( + withAPAgingSummaryActions, + withAPAgingSummary(({ payableAgingSummaryFilter }) => ({ + payableAgingFilter: payableAgingSummaryFilter, + })), +)(APAgingSummaryHeader); diff --git a/client/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryHeaderGeneral.js b/client/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryHeaderGeneral.js new file mode 100644 index 000000000..4d72cfeb7 --- /dev/null +++ b/client/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryHeaderGeneral.js @@ -0,0 +1,77 @@ +import React from 'react'; +import { FastField } from 'formik'; +import { DateInput } from '@blueprintjs/datetime'; +import { Intent, FormGroup, InputGroup, Position } from '@blueprintjs/core'; +import { FormattedMessage as T } from 'react-intl'; +import { Row, Col, FieldHint } from 'components'; +import { + momentFormatter, + tansformDateValue, + inputIntent, + handleDateChange, +} from 'utils'; + +/** + * AP Aging Summary - Drawer Header - General Fields. + */ +export default function APAgingSummaryHeaderGeneral() { + return ( +
+ + + + {({ form, field: { value }, meta: { error } }) => ( + } + labelInfo={} + fill={true} + intent={inputIntent({ error })} + > + { + form.setFieldValue('asDate', selectedDate); + })} + popoverProps={{ position: Position.BOTTOM, minimal: true }} + minimal={true} + fill={true} + /> + + )} + + + + + + + {({ field, meta: { error } }) => ( + } + labelInfo={} + intent={inputIntent({ error })} + > + + + )} + + + + + + + {({ field, meta: { error } }) => ( + } + labelInfo={} + intent={inputIntent({ error })} + > + + + )} + + + +
+ ); +} diff --git a/client/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryTable.js b/client/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryTable.js new file mode 100644 index 000000000..303d7c28b --- /dev/null +++ b/client/src/containers/FinancialStatements/APAgingSummary/APAgingSummaryTable.js @@ -0,0 +1,103 @@ +import React, { useMemo, useCallback } from 'react'; +import { FormattedMessage as T, useIntl } from 'react-intl'; +import { DataTable } from 'components'; +import FinancialSheet from 'components/FinancialSheet'; + +import withAPAgingSummary from './withAPAgingSummary'; + +import { compose, getColumnWidth } from 'utils'; + +/** + * AP aging summary table sheet. + */ +function APAgingSummaryTable({ + //#withPayableAgingSummary + payableAgingColumns, + payableAgingRows, + payableAgingLoading, + + //#ownProps + organizationName, +}) { + const { formatMessage } = useIntl(); + const agingColumns = useMemo( + () => + payableAgingColumns.map((agingColumn) => { + return `${agingColumn.before_days} - ${ + agingColumn.to_days || 'And Over' + }`; + }), + [payableAgingColumns], + ); + + const columns = useMemo( + () => [ + { + Header: , + accessor: 'name', + className: 'name', + width: 240, + sticky: 'left', + textOverview: true, + }, + { + Header: , + accessor: 'current', + className: 'current', + width: getColumnWidth(payableAgingRows, `current`, { + minWidth: 120, + }), + }, + + ...agingColumns.map((agingColumn, index) => ({ + Header: agingColumn, + accessor: `aging-${index}`, + width: getColumnWidth(payableAgingRows, `aging-${index}`, { + minWidth: 120, + }), + })), + { + Header: , + accessor: 'total', + width: getColumnWidth(payableAgingRows, 'total', { + minWidth: 120, + }), + }, + ], + [payableAgingRows], + ); + const rowClassNames = (row) => [`row-type--${row.original.rowType}`]; + + return ( + + + + ); +} + +export default compose( + withAPAgingSummary( + ({ + payableAgingSummaryLoading, + payableAgingSummaryColumns, + payableAgingSummaryRows, + }) => ({ + payableAgingLoading: payableAgingSummaryLoading, + payableAgingColumns: payableAgingSummaryColumns, + payableAgingRows: payableAgingSummaryRows, + }), + ), +)(APAgingSummaryTable); diff --git a/client/src/containers/FinancialStatements/APAgingSummary/common.js b/client/src/containers/FinancialStatements/APAgingSummary/common.js new file mode 100644 index 000000000..0cb3aaea0 --- /dev/null +++ b/client/src/containers/FinancialStatements/APAgingSummary/common.js @@ -0,0 +1,5 @@ +import { transformToCamelCase, flatObject } from 'utils'; + +export const transformFilterFormToQuery = (form) => { + return flatObject(transformToCamelCase(form)); +}; \ No newline at end of file diff --git a/client/src/containers/FinancialStatements/APAgingSummary/withAPAgingSummary.js b/client/src/containers/FinancialStatements/APAgingSummary/withAPAgingSummary.js new file mode 100644 index 000000000..9a0bed6b4 --- /dev/null +++ b/client/src/containers/FinancialStatements/APAgingSummary/withAPAgingSummary.js @@ -0,0 +1,35 @@ +import { connect } from 'react-redux'; +import { + getFinancialSheetFactory, + getFinancialSheetColumnsFactory, + getFinancialSheetTableRowsFactory, +} from 'store/financialStatement/financialStatements.selectors'; + +export default (mapState) => { + const mapStateToProps = (state, props) => { + const getAPAgingSheet = getFinancialSheetFactory('payableAgingSummary'); + const getAPAgingSheetColumns = getFinancialSheetColumnsFactory( + 'payableAgingSummary', + ); + const getAPAgingSheetRows = getFinancialSheetTableRowsFactory( + 'payableAgingSummary', + ); + + const { + loading, + filter, + refresh, + } = state.financialStatements.payableAgingSummary; + + const mapped = { + payableAgingSummarySheet: getAPAgingSheet(state, props), + payableAgingSummaryColumns: getAPAgingSheetColumns(state, props), + payableAgingSummaryRows: getAPAgingSheetRows(state, props), + payableAgingSummaryLoading: loading, + payableAgingSummaryFilter: filter, + APAgingSummaryRefresh: refresh, + }; + return mapState ? mapState(mapped, state, props) : mapped; + }; + return connect(mapStateToProps); +}; diff --git a/client/src/containers/FinancialStatements/APAgingSummary/withAPAgingSummaryActions.js b/client/src/containers/FinancialStatements/APAgingSummary/withAPAgingSummaryActions.js new file mode 100644 index 000000000..87cefd3d8 --- /dev/null +++ b/client/src/containers/FinancialStatements/APAgingSummary/withAPAgingSummaryActions.js @@ -0,0 +1,18 @@ +import { connect } from 'react-redux'; +import { + fetchPayableAginSummary, + payableAgingSummaryRefresh, +} from 'store/financialStatement/financialStatements.actions'; + +const mapActionsToProps = (dispatch) => ({ + requestPayableAgingSummary: (query) => + dispatch(fetchPayableAginSummary({ query })), + refreshAPAgingSummary: (refresh) => + dispatch(payableAgingSummaryRefresh(refresh)), + toggleFilterAPAgingSummary: () => + dispatch({ + type: 'PAYABLE_AGING_SUMMARY_FILTER_TOGGLE', + }), +}); + +export default connect(null, mapActionsToProps); diff --git a/client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummary.js b/client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummary.js index 54faeefe9..194bb575d 100644 --- a/client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummary.js +++ b/client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummary.js @@ -97,16 +97,17 @@ function ReceivableAgingSummarySheet({ const handleNumberFormatSubmit = (numberFormat) => { setQuery({ ...query, - numberFormat + numberFormat, }); refreshARAgingSummary(true); }; - + console.log(query, 'EE'); return ( + onNumberFormatSubmit={handleNumberFormatSubmit} + /> diff --git a/client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryActionsBar.js b/client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryActionsBar.js index 9059987cc..e511ad802 100644 --- a/client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryActionsBar.js +++ b/client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryActionsBar.js @@ -48,7 +48,6 @@ function ARAgingSummaryActionsBar({ const handleNumberFormatSubmit = (numberFormat) => { safeInvoke(onNumberFormatSubmit, numberFormat); }; - return ( @@ -98,7 +97,7 @@ function ARAgingSummaryActionsBar({ className={Classes.MINIMAL} text={} icon={} - /> + />