From 343185b8bdc2bf3a1e7b148f4ea0f1c26dd57e56 Mon Sep 17 00:00:00 2001 From: "a.bouhuolia" Date: Wed, 13 Jan 2021 20:58:58 +0200 Subject: [PATCH] feat: AR aging summary sheet frontend. --- client/src/components/DialogsContainer.js | 1 - .../ARAgingSummary/ARAgingSummary.js | 127 +++++++++++++++ .../ARAgingSummaryActionsBar.js | 94 +++++++++++ .../ARAgingSummary/ARAgingSummaryHeader.js | 98 ++++++++++++ .../ARAgingSummaryHeaderGeneral.js | 76 +++++++++ .../ARAgingSummary/ARAgingSummaryTable.js | 103 ++++++++++++ .../ARAgingSummary/common.js | 5 + .../ARAgingSummary/withARAgingSummary.js | 36 +++++ .../withARAgingSummaryActions.js} | 4 +- .../BalanceSheet/BalanceSheet.js | 2 +- .../BalanceSheet/BalanceSheetActionsBar.js | 8 +- .../ReceivableAgingSummary.js | 89 ----------- .../ReceivableAgingSummaryActionsBar.js | 110 ------------- .../ReceivableAgingSummaryHeader.js | 148 ------------------ .../ReceivableAgingSummaryTable.js | 99 ------------ .../withReceivableAgingSummary.js | 35 ----- .../withReceivableAgingSummaryTable.js | 14 -- client/src/lang/en/index.js | 1 + client/src/routes/dashboard.js | 22 +-- .../financialStatements.actions.js | 5 +- .../financialStatements.mappers.js | 42 +++++ .../financialStatements.reducer.js | 93 ++++------- .../src/style/pages/financial-statements.scss | 29 ++-- server/src/interfaces/ARAgingSummaryReport.ts | 1 + .../AgingSummary/ARAgingSummarySheet.ts | 2 + .../AgingSummary/AgingSummary.ts | 8 +- .../Inventory/InventoryAdjustmentService.ts | 12 +- 27 files changed, 670 insertions(+), 594 deletions(-) create mode 100644 client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummary.js create mode 100644 client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryActionsBar.js create mode 100644 client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryHeader.js create mode 100644 client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryHeaderGeneral.js create mode 100644 client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryTable.js create mode 100644 client/src/containers/FinancialStatements/ARAgingSummary/common.js create mode 100644 client/src/containers/FinancialStatements/ARAgingSummary/withARAgingSummary.js rename client/src/containers/FinancialStatements/{ReceivableAgingSummary/withReceivableAgingSummaryActions.js => ARAgingSummary/withARAgingSummaryActions.js} (84%) delete mode 100644 client/src/containers/FinancialStatements/ReceivableAgingSummary/ReceivableAgingSummary.js delete mode 100644 client/src/containers/FinancialStatements/ReceivableAgingSummary/ReceivableAgingSummaryActionsBar.js delete mode 100644 client/src/containers/FinancialStatements/ReceivableAgingSummary/ReceivableAgingSummaryHeader.js delete mode 100644 client/src/containers/FinancialStatements/ReceivableAgingSummary/ReceivableAgingSummaryTable.js delete mode 100644 client/src/containers/FinancialStatements/ReceivableAgingSummary/withReceivableAgingSummary.js delete mode 100644 client/src/containers/FinancialStatements/ReceivableAgingSummary/withReceivableAgingSummaryTable.js diff --git a/client/src/components/DialogsContainer.js b/client/src/components/DialogsContainer.js index 6277ace96..61f694480 100644 --- a/client/src/components/DialogsContainer.js +++ b/client/src/components/DialogsContainer.js @@ -1,7 +1,6 @@ import React, { lazy } from 'react'; import AccountFormDialog from 'containers/Dialogs/AccountFormDialog'; - import InviteUserDialog from 'containers/Dialogs/InviteUserDialog'; import ItemCategoryDialog from 'containers/Dialogs/ItemCategoryDialog'; import CurrencyFormDialog from 'containers/Dialogs/CurrencyFormDialog'; diff --git a/client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummary.js b/client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummary.js new file mode 100644 index 000000000..3e1090854 --- /dev/null +++ b/client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummary.js @@ -0,0 +1,127 @@ +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 ARAgingSummaryActionsBar from './ARAgingSummaryActionsBar'; +import DashboardPageContent from 'components/Dashboard/DashboardPageContent'; +import ARAgingSummaryHeader from './ARAgingSummaryHeader'; +import ReceivableAgingSummaryTable from './ARAgingSummaryTable'; + +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 { transfromFilterFormToQuery } from './common'; + +/** + * AR aging summary report. + */ +function ReceivableAgingSummarySheet({ + // #withSettings + organizationName, + + // #withDashboardActions + changePageTitle, + setDashboardBackLink, + + // #withARAgingSummaryActions + requestReceivableAgingSummary, + refreshARAgingSummary, + toggleFilterARAgingSummary, + + // #withARAgingSummary + ARAgingSummaryRefresh, +}) { + const { formatMessage } = useIntl(); + const [query, setQuery] = useState({ + asDate: moment().endOf('day').format('YYYY-MM-DD'), + agingBeforeDays: 30, + agingPeriods: 3, + }); + + useEffect(() => { + changePageTitle(formatMessage({ id: 'receivable_aging_summary' })); + }, [changePageTitle, formatMessage]); + + useEffect(() => { + if (ARAgingSummaryRefresh) { + queryCache.invalidateQueries('receivable-aging-summary'); + refreshARAgingSummary(false); + } + }, [ARAgingSummaryRefresh, refreshARAgingSummary]); + + useEffect(() => { + // Show the back link on dashboard topbar. + setDashboardBackLink(true); + + return () => { + // Hide the back link on dashboard topbar. + setDashboardBackLink(false); + }; + }, [setDashboardBackLink]); + + // 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( + (filter) => { + const _filter = { + ...filter, + asDate: moment(filter.asDate).format('YYYY-MM-DD'), + }; + setQuery(_filter); + refreshARAgingSummary(true); + toggleFilterARAgingSummary(false); + }, + [refreshARAgingSummary, toggleFilterARAgingSummary], + ); + + return ( + + + + + + +
+ +
+
+
+
+ ); +} + +export default compose( + withDashboardActions, + withARAgingSummaryActions, + withSettings(({ organizationSettings }) => ({ + organizationName: organizationSettings.name, + })), + withARAgingSummary(({ ARAgingSummaryRefresh }) => ({ + ARAgingSummaryRefresh: ARAgingSummaryRefresh, + })), +)(ReceivableAgingSummarySheet); diff --git a/client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryActionsBar.js b/client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryActionsBar.js new file mode 100644 index 000000000..cd826052c --- /dev/null +++ b/client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryActionsBar.js @@ -0,0 +1,94 @@ +import React from 'react'; +import { + NavbarDivider, + NavbarGroup, + Classes, + Button, + Popover, + PopoverInteractionKind, + Position, +} from '@blueprintjs/core'; +import { FormattedMessage as T } from 'react-intl'; +import classNames from 'classnames'; + +import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar'; +import Icon from 'components/Icon'; + +import withARAgingSummary from './withARAgingSummary'; +import withARAgingSummaryActions from './withARAgingSummaryActions'; + +import { compose } from 'utils'; + +/** + * AR Aging summary sheet - Actions bar. + */ +function ARAgingSummaryActionsBar({ + // #withReceivableAging + receivableAgingFilter, + + // #withReceivableAgingActions + toggleFilterARAgingSummary, + refreshARAgingSummary, +}) { + const handleFilterToggleClick = () => { + toggleFilterARAgingSummary(); + }; + // Handles re-calculate report button. + const handleRecalcReport = () => { + refreshARAgingSummary(true); + }; + + return ( + + + + + + + + + ); +} + +export default compose( + withARAgingSummaryActions, + withARAgingSummary( + ({ receivableAgingSummaryFilter, receivableAgingSummaryRefresh }) => ({ + receivableAgingFilter: receivableAgingSummaryFilter, + receivableAgingRefresh: receivableAgingSummaryRefresh, + }), + ), +)(ARAgingSummaryHeader); diff --git a/client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryHeaderGeneral.js b/client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryHeaderGeneral.js new file mode 100644 index 000000000..c90dd9554 --- /dev/null +++ b/client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryHeaderGeneral.js @@ -0,0 +1,76 @@ +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 } from 'utils'; + +/** + * AR Aging Summary - Drawer Header - General Fields. + */ +export default function ARAgingSummaryHeaderGeneral({}) { + return ( +
+ + + + {({ form, field: { value }, meta: { error, touched } }) => ( + } + labelInfo={} + fill={true} + intent={error && Intent.DANGER} + > + { + form.setFieldValue('asDate', selectedDate); + }} + popoverProps={{ position: Position.BOTTOM, minimal: true }} + minimal={true} + fill={true} + /> + + )} + + + + + + + + {({ field, meta: { error, touched } }) => ( + } + labelInfo={} + className={'form-group--aging-before-days'} + intent={error && Intent.DANGER} + > + + + )} + + + + + + + + {({ field, meta: { error, touched } }) => ( + } + labelInfo={} + className={'form-group--aging-periods'} + intent={error && Intent.DANGER} + > + + + )} + + + +
+ ); +} diff --git a/client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryTable.js b/client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryTable.js new file mode 100644 index 000000000..9e2db87b7 --- /dev/null +++ b/client/src/containers/FinancialStatements/ARAgingSummary/ARAgingSummaryTable.js @@ -0,0 +1,103 @@ +import React, { useMemo, useCallback } from 'react'; +import { FormattedMessage as T, useIntl } from 'react-intl'; +import DataTable from 'components/DataTable'; +import FinancialSheet from 'components/FinancialSheet'; + +import withARAgingSummary from './withARAgingSummary'; + +import { compose } from 'utils'; + +/** + * AR aging summary table sheet. + */ +function ReceivableAgingSummaryTable({ + // #withReceivableAgingSummary + receivableAgingRows, + receivableAgingLoading, + receivableAgingColumns, + + // #ownProps + onFetchData, + organizationName, +}) { + const { formatMessage } = useIntl(); + + const agingColumns = useMemo(() => { + return receivableAgingColumns.map((agingColumn) => { + return `${agingColumn.before_days} - ${ + agingColumn.to_days || 'And Over' + }`; + }); + }, [receivableAgingColumns]); + + const columns = useMemo( + () => [ + { + Header: , + accessor: 'name', + className: 'customer_name', + sticky: 'left', + width: 200, + }, + { + Header: , + accessor: 'current', + className: 'current', + width: 120, + }, + ...agingColumns.map((agingColumn, index) => ({ + Header: agingColumn, + accessor: `aging-${index }`, + width: 120, + })), + { + Header: (), + id: 'total', + accessor: 'total', + className: 'total', + width: 140, + }, + ], + [agingColumns], + ); + + const rowClassNames = (row) => [`row-type--${row.original.rowType}`]; + + const handleFetchData = useCallback((...args) => { + // onFetchData && onFetchData(...args); + }, []); + + return ( + + + + ); +} + +export default compose( + withARAgingSummary( + ({ + receivableAgingSummaryLoading, + receivableAgingSummaryColumns, + receivableAgingSummaryRows, + }) => ({ + receivableAgingLoading: receivableAgingSummaryLoading, + receivableAgingColumns: receivableAgingSummaryColumns, + receivableAgingRows: receivableAgingSummaryRows, + }), + ), +)(ReceivableAgingSummaryTable); diff --git a/client/src/containers/FinancialStatements/ARAgingSummary/common.js b/client/src/containers/FinancialStatements/ARAgingSummary/common.js new file mode 100644 index 000000000..96bd39a7e --- /dev/null +++ b/client/src/containers/FinancialStatements/ARAgingSummary/common.js @@ -0,0 +1,5 @@ +import { mapKeys, snakeCase } from 'lodash'; + +export const transfromFilterFormToQuery = (form) => { + return mapKeys(form, (v, k) => snakeCase(k)); +}; \ No newline at end of file diff --git a/client/src/containers/FinancialStatements/ARAgingSummary/withARAgingSummary.js b/client/src/containers/FinancialStatements/ARAgingSummary/withARAgingSummary.js new file mode 100644 index 000000000..c2a93c923 --- /dev/null +++ b/client/src/containers/FinancialStatements/ARAgingSummary/withARAgingSummary.js @@ -0,0 +1,36 @@ +import { connect } from 'react-redux'; +import { + getFinancialSheetFactory, + getFinancialSheetAccountsFactory, + getFinancialSheetColumnsFactory, + getFinancialSheetQueryFactory, + getFinancialSheetTableRowsFactory, +} from 'store/financialStatement/financialStatements.selectors'; + +export default (mapState) => { + const mapStateToProps = (state, props) => { + const getARAgingSheet = getFinancialSheetFactory('receivableAgingSummary'); + const getARAgingSheetColumns = getFinancialSheetColumnsFactory( + 'receivableAgingSummary', + ); + const getARAgingSheetRows = getFinancialSheetTableRowsFactory( + 'receivableAgingSummary', + ); + const { + loading, + filter, + refresh, + } = state.financialStatements.receivableAgingSummary; + + const mapped = { + receivableAgingSummarySheet: getARAgingSheet(state, props), + receivableAgingSummaryColumns: getARAgingSheetColumns(state, props), + receivableAgingSummaryRows: getARAgingSheetRows(state, props), + receivableAgingSummaryLoading: loading, + receivableAgingSummaryFilter: filter, + ARAgingSummaryRefresh: refresh, + }; + return mapState ? mapState(mapped, state, props) : mapped; + }; + return connect(mapStateToProps); +}; diff --git a/client/src/containers/FinancialStatements/ReceivableAgingSummary/withReceivableAgingSummaryActions.js b/client/src/containers/FinancialStatements/ARAgingSummary/withARAgingSummaryActions.js similarity index 84% rename from client/src/containers/FinancialStatements/ReceivableAgingSummary/withReceivableAgingSummaryActions.js rename to client/src/containers/FinancialStatements/ARAgingSummary/withARAgingSummaryActions.js index 2e0923a12..228e233d6 100644 --- a/client/src/containers/FinancialStatements/ReceivableAgingSummary/withReceivableAgingSummaryActions.js +++ b/client/src/containers/FinancialStatements/ARAgingSummary/withARAgingSummaryActions.js @@ -7,11 +7,11 @@ import { const mapActionsToProps = (dispatch) => ({ requestReceivableAgingSummary: (query) => dispatch(fetchReceivableAgingSummary({ query })), - toggleFilterReceivableAgingSummary: () => + toggleFilterARAgingSummary: () => dispatch({ type: 'RECEIVABLE_AGING_SUMMARY_FILTER_TOGGLE', }), - refreshReceivableAgingSummary: (refresh) => + refreshARAgingSummary: (refresh) => dispatch(receivableAgingSummaryRefresh(refresh)), }); diff --git a/client/src/containers/FinancialStatements/BalanceSheet/BalanceSheet.js b/client/src/containers/FinancialStatements/BalanceSheet/BalanceSheet.js index 5446c9d54..0e8eeffa3 100644 --- a/client/src/containers/FinancialStatements/BalanceSheet/BalanceSheet.js +++ b/client/src/containers/FinancialStatements/BalanceSheet/BalanceSheet.js @@ -71,7 +71,7 @@ function BalanceSheet({ // Hide the back link on dashboard topbar. setDashboardBackLink(false); }; - }); + }, [setDashboardBackLink]); // Handle re-fetch balance sheet after filter change. const handleFilterSubmit = useCallback( diff --git a/client/src/containers/FinancialStatements/BalanceSheet/BalanceSheetActionsBar.js b/client/src/containers/FinancialStatements/BalanceSheet/BalanceSheetActionsBar.js index ad79d6d36..c03943d8d 100644 --- a/client/src/containers/FinancialStatements/BalanceSheet/BalanceSheetActionsBar.js +++ b/client/src/containers/FinancialStatements/BalanceSheet/BalanceSheetActionsBar.js @@ -49,7 +49,13 @@ function BalanceSheetActionsBar({