diff --git a/client/src/config/financialReportsMenu.js b/client/src/config/financialReportsMenu.js index f32beaf2f..fc82eef1b 100644 --- a/client/src/config/financialReportsMenu.js +++ b/client/src/config/financialReportsMenu.js @@ -10,7 +10,8 @@ export const financialReportMenus = [ }, { title: 'Trial Balance Sheet', - desc: 'Summarizes the credit and debit balance of each account in your chart of accounts at a specific point in time.', + desc: + 'Summarizes the credit and debit balance of each account in your chart of accounts at a specific point in time.', link: '/financial-reports/trial-balance-sheet', }, { @@ -21,22 +22,26 @@ export const financialReportMenus = [ }, { title: 'Profit/Loss Report', - desc: "Reports the revenues, costs and expenses incurred during a specific point in time with comparison period(s).", + desc: + 'Reports the revenues, costs and expenses incurred during a specific point in time with comparison period(s).', link: '/financial-reports/profit-loss-sheet', }, { title: 'General Ledger Report', - desc: "Reports every transaction going in and out of your accounts and organized by accounts and date to monitoring activity of accounts.", + desc: + 'Reports every transaction going in and out of your accounts and organized by accounts and date to monitoring activity of accounts.', link: '/financial-reports/general-ledger', }, { title: 'Receivable Aging Summary', - desc: "Summarize total unpaid balances of customers invoices with number of days the unpaid invoice is overdue.", + desc: + 'Summarize total unpaid balances of customers invoices with number of days the unpaid invoice is overdue.', link: '/financial-reports/receivable-aging-summary', }, { title: 'Payable Aging Summary', - desc: "Summarize total unpaid balances of vendors purchase invoices with the number of days the unpaid invoice is overdue.", + desc: + 'Summarize total unpaid balances of vendors purchase invoices with the number of days the unpaid invoice is overdue.', link: '/financial-reports/payable-aging-summary', }, ], @@ -54,16 +59,37 @@ export const SalesAndPurchasesReportMenus = [ link: '/financial-reports/purchases-by-items', }, { - title: 'Sales by Items', + title: 'Sales By Items', desc: - "Summarize the business’s sold items quantity, income and average income rate of each item during a specific point in time.", + 'Summarize the business’s sold items quantity, income and average income rate of each item during a specific point in time.', link: '/financial-reports/sales-by-items', }, { title: 'Inventory valuation', - desc: 'Summarize the business’s purchase items quantity, cost and average cost rate of each item during a specific point in time.', + desc: + 'Summarize the business’s purchase items quantity, cost and average cost rate of each item during a specific point in time.', link: '/financial-reports/inventory-valuation', }, + { + title: 'Customer Balance summary', + desc: '', + link: '/financial-reports/customers-balance-summary', + }, + { + title: 'Vendors Balance summary', + desc: '', + link: '/financial-reports/vendors-balance-summary', + }, + { + title: 'Customers Transactions', + desc: '', + link: '/financial-reports/transactions-by-customers', + }, + { + title: 'Vendors Transactions', + desc: '', + link: '/financial-reports/transactions-by-vendors', + }, ], }, ]; diff --git a/client/src/containers/FinancialStatements/CustomersBalanceSummary/CustomersBalanceSummary.js b/client/src/containers/FinancialStatements/CustomersBalanceSummary/CustomersBalanceSummary.js new file mode 100644 index 000000000..f45480599 --- /dev/null +++ b/client/src/containers/FinancialStatements/CustomersBalanceSummary/CustomersBalanceSummary.js @@ -0,0 +1,87 @@ +import React, { useEffect, useState } from 'react'; +import moment from 'moment'; + +import 'style/pages/FinancialStatements/ContactsBalanceSummary.scss'; + +import { FinancialStatement } from 'components'; +import DashboardPageContent from 'components/Dashboard/DashboardPageContent'; + +import CustomersBalanceSummaryActionsBar from './CustomersBalanceSummaryActionsBar'; +import CustomersBalanceSummaryHeader from './CustomersBalanceSummaryHeader'; +import CustomersBalanceSummaryTable from './CustomersBalanceSummaryTable'; + +import { CustomersBalanceLoadingBar } from './components'; +import { CustomersBalanceSummaryProvider } from './CustomersBalanceSummaryProvider'; +import withCustomersBalanceSummaryActions from './withCustomersBalanceSummaryActions'; + +import withSettings from 'containers/Settings/withSettings'; + +import { compose } from 'redux'; + +/** + * Customers Balance summary. + */ +function CustomersBalanceSummary({ + // #withPreferences + organizationName, + + // #withCustomersBalanceSummaryActions + toggleCustomerBalanceFilterDrawer, +}) { + + const [filter, setFilter] = useState({ + asDate: moment().endOf('day').format('YYYY-MM-DD'), + }); + + // Handle re-fetch customers balance summary after filter change. + const handleFilterSubmit = (filter) => { + const _filter = { + ...filter, + asDate: moment(filter.asDate).format('YYYY-MM-DD'), + }; + setFilter({ ..._filter }); + }; + + // Handle number format. + const handleNumberFormat = (values) => { + setFilter({ + ...filter, + numberFormat: values, + }); + }; + + useEffect( + () => () => { + toggleCustomerBalanceFilterDrawer(false); + }, + [toggleCustomerBalanceFilterDrawer], + ); + + return ( + + + + + + + +
+ +
+
+
+
+ ); +} +export default compose( + withSettings(({ organizationSettings }) => ({ + organizationName: organizationSettings.name, + })), + withCustomersBalanceSummaryActions, +)(CustomersBalanceSummary); diff --git a/client/src/containers/FinancialStatements/CustomersBalanceSummary/CustomersBalanceSummaryActionsBar.js b/client/src/containers/FinancialStatements/CustomersBalanceSummary/CustomersBalanceSummaryActionsBar.js new file mode 100644 index 000000000..d70519dd5 --- /dev/null +++ b/client/src/containers/FinancialStatements/CustomersBalanceSummary/CustomersBalanceSummaryActionsBar.js @@ -0,0 +1,133 @@ +import React from 'react'; +import { + NavbarGroup, + Button, + Classes, + NavbarDivider, + Popover, + PopoverInteractionKind, + Position, +} from '@blueprintjs/core'; +import { FormattedMessage as T } from 'react-intl'; +import classNames from 'classnames'; + +import Icon from 'components/Icon'; +import DashboardActionsBar from 'components/Dashboard/DashboardActionsBar'; +import NumberFormatDropdown from 'components/NumberFormatDropdown'; + +import withCustomersBalanceSummary from './withCustomersBalanceSummary'; +import withCustomersBalanceSummaryActions from './withCustomersBalanceSummaryActions'; +import { useCustomersBalanceSummaryContext } from './CustomersBalanceSummaryProvider'; +import { compose, saveInvoke } from 'utils'; + +/** + * customer balance summary action bar. + */ +function CustomersBalanceSummaryActionsBar({ + // #ownProps + numberFormat, + onNumberFormatSubmit, + + //#withCustomersBalanceSummary + isFilterDrawerOpen, + + //#withCustomersBalanceSummaryActions + toggleCustomerBalanceFilterDrawer, +}) { + const { + refetch, + isCustomersBalanceLoading, + } = useCustomersBalanceSummaryContext(); + + // handle filter toggle click. + const handleFilterToggleClick = () => { + toggleCustomerBalanceFilterDrawer(); + }; + + // Handle recalculate the report button. + const handleRecalcReport = () => { + refetch(); + }; + + // Handle number format form submit. + const handleNumberFormatSubmit = (values) => { + saveInvoke(onNumberFormatSubmit, values); + }; + + return ( + + + + + + + + + ); +} + +export default compose( + withCustomersBalanceSummary(({ customersBalanceDrawerFilter }) => ({ + customersBalanceDrawerFilter, + })), + withCustomersBalanceSummaryActions, +)(CustomersBalanceSummaryHeader); diff --git a/client/src/containers/FinancialStatements/CustomersBalanceSummary/CustomersBalanceSummaryProvider.js b/client/src/containers/FinancialStatements/CustomersBalanceSummary/CustomersBalanceSummaryProvider.js new file mode 100644 index 000000000..8ab7f48ab --- /dev/null +++ b/client/src/containers/FinancialStatements/CustomersBalanceSummary/CustomersBalanceSummaryProvider.js @@ -0,0 +1,42 @@ +import React, { createContext, useContext } from 'react'; +import FinancialReportPage from '../FinancialReportPage'; +import { useCustomerBalanceSummaryReport } from 'hooks/query'; +import { transformFilterFormToQuery } from '../common'; + +const CustomersBalanceSummaryContext = createContext(); + +/** + * Customers balance summary provider. + */ +function CustomersBalanceSummaryProvider({ filter, ...props }) { + + // const query = React.useMemo(() => transformFilterFormToQuery(filter), [ + // filter, + // ]); + + const { + data: CustomerBalanceSummary, + isLoading: isCustomersBalanceLoading, + isFetching: isCustomersBalanceFetching, + refetch + } = useCustomerBalanceSummaryReport(filter, { + keepPreviousData: true, + }); + + const provider = { + CustomerBalanceSummary, + isCustomersBalanceFetching, + isCustomersBalanceLoading, + refetch, + }; + return ( + + + + ); +} + +const useCustomersBalanceSummaryContext = () => + useContext(CustomersBalanceSummaryContext); + +export { CustomersBalanceSummaryProvider, useCustomersBalanceSummaryContext }; diff --git a/client/src/containers/FinancialStatements/CustomersBalanceSummary/CustomersBalanceSummaryTable.js b/client/src/containers/FinancialStatements/CustomersBalanceSummary/CustomersBalanceSummaryTable.js new file mode 100644 index 000000000..57ee2655f --- /dev/null +++ b/client/src/containers/FinancialStatements/CustomersBalanceSummary/CustomersBalanceSummaryTable.js @@ -0,0 +1,48 @@ +import React, { useMemo, useCallback } from 'react'; +import { useIntl } from 'react-intl'; +import classNames from 'classnames'; + +import FinancialSheet from 'components/FinancialSheet'; +import DataTable from 'components/DataTable'; + +import { useCustomersBalanceSummaryContext } from './CustomersBalanceSummaryProvider'; +import { useCustomersSummaryColumns } from './components'; + +/** + * customers balance summary table. + */ +export default function CustomersBalanceSummaryTable({ + // #ownProps + companyName, +}) { + const { formatMessage } = useIntl(); + + const { + isCustomersBalanceLoading, + CustomerBalanceSummary: { tableRows }, + } = useCustomersBalanceSummaryContext(); + + const columns = useCustomersSummaryColumns(); + + const rowClassNames = (row) => { + return [`row-type--${row.original.rowTypes}`]; + }; + + return ( + + + + ); +} diff --git a/client/src/containers/FinancialStatements/CustomersBalanceSummary/components.js b/client/src/containers/FinancialStatements/CustomersBalanceSummary/components.js new file mode 100644 index 000000000..0ac61d5c9 --- /dev/null +++ b/client/src/containers/FinancialStatements/CustomersBalanceSummary/components.js @@ -0,0 +1,48 @@ +import React from 'react'; +import { formatMessage } from 'services/intl'; + +import { If } from 'components'; +import FinancialLoadingBar from '../FinancialLoadingBar'; +import { useCustomersBalanceSummaryContext } from './CustomersBalanceSummaryProvider'; + +/** + * Retrieve customers balance summary columns. + */ +export const useCustomersSummaryColumns = () => { + return React.useMemo( + () => [ + { + Header: formatMessage({ id: 'customer_name' }), + accessor: 'cells[0].value', + className: 'customer_name', + width: 240, + }, + { + Header: formatMessage({ id: 'total' }), + accessor: 'cells[1].value', + className: 'total', + width: 140, + }, + { + Header: formatMessage({ id: 'percentage_of_column' }), + accessor: 'cells[2].value', + className: 'total', + width: 140, + }, + ], + [formatMessage], + ); +}; + +/** + * customers balance summary loading bar. + */ +export function CustomersBalanceLoadingBar() { + const { isCustomersBalanceFetching } = useCustomersBalanceSummaryContext(); + + return ( + + + + ); +} diff --git a/client/src/containers/FinancialStatements/CustomersBalanceSummary/withCustomersBalanceSummary.js b/client/src/containers/FinancialStatements/CustomersBalanceSummary/withCustomersBalanceSummary.js new file mode 100644 index 000000000..80cf7382a --- /dev/null +++ b/client/src/containers/FinancialStatements/CustomersBalanceSummary/withCustomersBalanceSummary.js @@ -0,0 +1,15 @@ +import { connect } from 'react-redux'; +import { getCustomersBalanceSummaryFilterDrawer } from 'store/financialStatement/financialStatements.selectors'; + +export default (mapState) => { + const mapStateToProps = (state, props) => { + const mapped = { + customersBalanceDrawerFilter: getCustomersBalanceSummaryFilterDrawer( + state, + props, + ), + }; + return mapState ? mapState(mapped, state, props) : mapped; + }; + return connect(mapStateToProps); +}; diff --git a/client/src/containers/FinancialStatements/CustomersBalanceSummary/withCustomersBalanceSummaryActions.js b/client/src/containers/FinancialStatements/CustomersBalanceSummary/withCustomersBalanceSummaryActions.js new file mode 100644 index 000000000..b7679f2b1 --- /dev/null +++ b/client/src/containers/FinancialStatements/CustomersBalanceSummary/withCustomersBalanceSummaryActions.js @@ -0,0 +1,9 @@ +import { connect } from 'react-redux'; +import { toggleCustomersBalanceSummaryFilterDrawer } from 'store/financialStatement/financialStatements.actions'; + +const mapActionsToProps = (dispatch) => ({ + toggleCustomerBalanceFilterDrawer: (toggle) => + dispatch(toggleCustomersBalanceSummaryFilterDrawer(toggle)), +}); + +export default connect(null, mapActionsToProps);