mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-18 13:50:31 +00:00
Compare commits
86 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
96635ffa84 | ||
|
|
e874b89d2d | ||
|
|
60d37e3424 | ||
|
|
8ae39bf04c | ||
|
|
e3f2c82a38 | ||
|
|
68c0678dc3 | ||
|
|
030be9652c | ||
|
|
554527f17d | ||
|
|
79144ad4a5 | ||
|
|
e6fcbfeea6 | ||
|
|
7eacaa0660 | ||
|
|
673808cceb | ||
|
|
f27ef2c9b0 | ||
|
|
2986b537d0 | ||
|
|
b1f07d281f | ||
|
|
1b0ffb5574 | ||
|
|
b249335a73 | ||
|
|
4cc0a8c41e | ||
|
|
2e7061260e | ||
|
|
46570c5218 | ||
|
|
72a7c4890e | ||
|
|
a9a877f4fc | ||
|
|
cc42c21f24 | ||
|
|
2f0322b4fc | ||
|
|
b9418d3eb6 | ||
|
|
526181aa68 | ||
|
|
d445fec8c0 | ||
|
|
1f81fd213d | ||
|
|
83cd7ca893 | ||
|
|
d22143c97e | ||
|
|
200a59d6da | ||
|
|
8b4d841023 | ||
|
|
c361a5852c | ||
|
|
b759d7327e | ||
|
|
93df479c05 | ||
|
|
d300231838 | ||
|
|
47f6845633 | ||
|
|
f204b81407 | ||
|
|
2c2740ea73 | ||
|
|
c72802d683 | ||
|
|
b4f6d2c7f1 | ||
|
|
4456343eb6 | ||
|
|
a3d250cdc8 | ||
|
|
ce223e7e2f | ||
|
|
8d6ed9be41 | ||
|
|
e296507a96 | ||
|
|
3d78d2d051 | ||
|
|
fa455152a3 | ||
|
|
34501a9a61 | ||
|
|
066df28257 | ||
|
|
77d826e6d4 | ||
|
|
735803f1a5 | ||
|
|
354d1e8f75 | ||
|
|
225619be60 | ||
|
|
85a78b3809 | ||
|
|
da699a766a | ||
|
|
a958c6088a | ||
|
|
572d59577c | ||
|
|
7a0d506395 | ||
|
|
21ae8aabfc | ||
|
|
8f267b98e4 | ||
|
|
dcfe92076b | ||
|
|
79cb7f1a1d | ||
|
|
1380e288e0 | ||
|
|
b055908e12 | ||
|
|
20c140474b | ||
|
|
9ee5eba92b | ||
|
|
e755a2a318 | ||
|
|
1656691940 | ||
|
|
dd7d11ffb7 | ||
|
|
5c847be420 | ||
|
|
da3193195c | ||
|
|
e3141250b6 | ||
|
|
f1899e1ce1 | ||
|
|
76d6cd0eaa | ||
|
|
90b4f86a0d | ||
|
|
5766d25bd1 | ||
|
|
6a5d96e869 | ||
|
|
69f16d1977 | ||
|
|
9973693a86 | ||
|
|
11851d114d | ||
|
|
3a3dd7a565 | ||
|
|
687dda1e7c | ||
|
|
bfa809c831 | ||
|
|
07145e92ab | ||
|
|
21779007be |
14
CHANGELOG.md
14
CHANGELOG.md
@@ -2,6 +2,20 @@
|
|||||||
|
|
||||||
All notable changes to Bigcapital server-side will be in this file.
|
All notable changes to Bigcapital server-side will be in this file.
|
||||||
|
|
||||||
|
## [1.5.8] - 13-01-2022
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- Add payment receive PDF print.
|
||||||
|
- Add credit note PDF print.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
- fix: Payment receive initial loading state depends on request loading state instead fetching.
|
||||||
|
- fix: Balance sheet report alert positioning.
|
||||||
|
- fix: Separate customer and vendor inactivate and activate alerts.
|
||||||
|
- fix: Hide convert to invoice button if the invoice is already converted.
|
||||||
|
- fix: Customer and vendor balance summary percentage of column option.
|
||||||
|
- fix: Remove duplicated details in sales and purchases details drawers.
|
||||||
|
|
||||||
## [1.5.3] - 03-01-2020
|
## [1.5.3] - 03-01-2020
|
||||||
|
|
||||||
### Fixed
|
### Fixed
|
||||||
|
|||||||
@@ -85,6 +85,9 @@ function getClientEnvironment(publicUrl) {
|
|||||||
WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST,
|
WDS_SOCKET_HOST: process.env.WDS_SOCKET_HOST,
|
||||||
WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH,
|
WDS_SOCKET_PATH: process.env.WDS_SOCKET_PATH,
|
||||||
WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT,
|
WDS_SOCKET_PORT: process.env.WDS_SOCKET_PORT,
|
||||||
|
|
||||||
|
// Application version.
|
||||||
|
VERSION: paths.appVersion
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
// Stringify all values so we can feed into webpack DefinePlugin
|
// Stringify all values so we can feed into webpack DefinePlugin
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ const resolveModule = (resolveFn, filePath) => {
|
|||||||
return resolveFn(`${filePath}.js`);
|
return resolveFn(`${filePath}.js`);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const appVersion = require(resolveApp('package.json')).version;
|
||||||
|
|
||||||
// config after eject: we're in ./config/
|
// config after eject: we're in ./config/
|
||||||
module.exports = {
|
module.exports = {
|
||||||
dotenv: resolveApp('.env'),
|
dotenv: resolveApp('.env'),
|
||||||
@@ -65,6 +67,7 @@ module.exports = {
|
|||||||
proxySetup: resolveApp('src/setupProxy.js'),
|
proxySetup: resolveApp('src/setupProxy.js'),
|
||||||
appNodeModules: resolveApp('node_modules'),
|
appNodeModules: resolveApp('node_modules'),
|
||||||
publicUrlOrPath,
|
publicUrlOrPath,
|
||||||
|
appVersion
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "bigcapital-client",
|
"name": "bigcapital-client",
|
||||||
"version": "1.5.3",
|
"version": "1.5.8",
|
||||||
"private": true,
|
"private": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/core": "7.8.4",
|
"@babel/core": "7.8.4",
|
||||||
@@ -72,6 +72,7 @@
|
|||||||
"postcss-preset-env": "6.7.0",
|
"postcss-preset-env": "6.7.0",
|
||||||
"postcss-rtl": "^1.7.3",
|
"postcss-rtl": "^1.7.3",
|
||||||
"postcss-safe-parser": "4.0.1",
|
"postcss-safe-parser": "4.0.1",
|
||||||
|
"query-string": "^7.1.1",
|
||||||
"ramda": "^0.27.1",
|
"ramda": "^0.27.1",
|
||||||
"react": "^16.12.0",
|
"react": "^16.12.0",
|
||||||
"react-app-polyfill": "^1.0.6",
|
"react-app-polyfill": "^1.0.6",
|
||||||
@@ -93,7 +94,7 @@
|
|||||||
"react-sortablejs": "^2.0.11",
|
"react-sortablejs": "^2.0.11",
|
||||||
"react-split-pane": "^0.1.91",
|
"react-split-pane": "^0.1.91",
|
||||||
"react-table": "^7.6.3",
|
"react-table": "^7.6.3",
|
||||||
"react-table-sticky": "^1.1.2",
|
"react-table-sticky": "^1.1.3",
|
||||||
"react-transition-group": "^4.4.1",
|
"react-transition-group": "^4.4.1",
|
||||||
"react-use": "^13.26.1",
|
"react-use": "^13.26.1",
|
||||||
"react-use-context-menu": "^0.1.4",
|
"react-use-context-menu": "^0.1.4",
|
||||||
|
|||||||
@@ -2,7 +2,11 @@
|
|||||||
<html dir="ltr" lang="en">
|
<html dir="ltr" lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<link rel="icon" href="%PUBLIC_URL%/favicons/favicon-32.ico" sizes="32x32">
|
<link
|
||||||
|
rel="icon"
|
||||||
|
href="%PUBLIC_URL%/favicons/favicon-32.ico"
|
||||||
|
sizes="32x32"
|
||||||
|
/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<meta name="theme-color" content="#000000" />
|
<meta name="theme-color" content="#000000" />
|
||||||
<meta
|
<meta
|
||||||
@@ -15,6 +19,25 @@
|
|||||||
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/
|
||||||
-->
|
-->
|
||||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
|
||||||
|
|
||||||
|
<% if (process.env.NODE_ENV === 'production') { %>
|
||||||
|
<!-- Hotjar Tracking Code for https://app.bigcapital.ly/ -->
|
||||||
|
<script>
|
||||||
|
(function (h, o, t, j, a, r) {
|
||||||
|
h.hj =
|
||||||
|
h.hj ||
|
||||||
|
function () {
|
||||||
|
(h.hj.q = h.hj.q || []).push(arguments);
|
||||||
|
};
|
||||||
|
h._hjSettings = { hjid: 2774528, hjsv: 6 };
|
||||||
|
a = o.getElementsByTagName('head')[0];
|
||||||
|
r = o.createElement('script');
|
||||||
|
r.async = 1;
|
||||||
|
r.src = t + h._hjSettings.hjid + j + h._hjSettings.hjsv;
|
||||||
|
a.appendChild(r);
|
||||||
|
})(window, document, 'https://static.hotjar.com/c/hotjar-', '.js?sv=');
|
||||||
|
</script>
|
||||||
|
<% } %>
|
||||||
<!--
|
<!--
|
||||||
Notice the use of %PUBLIC_URL% in the tags above.
|
Notice the use of %PUBLIC_URL% in the tags above.
|
||||||
It will be replaced with the URL of the `public` folder during the build.
|
It will be replaced with the URL of the `public` folder during the build.
|
||||||
@@ -41,7 +64,11 @@
|
|||||||
To create a production bundle, use `npm run build` or `yarn build`.
|
To create a production bundle, use `npm run build` or `yarn build`.
|
||||||
-->
|
-->
|
||||||
|
|
||||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/flexboxgrid/6.3.1/flexboxgrid.min.css" type="text/css" >
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://cdnjs.cloudflare.com/ajax/libs/flexboxgrid/6.3.1/flexboxgrid.min.css"
|
||||||
|
type="text/css"
|
||||||
|
/>
|
||||||
<!-- <link href="https://cdn.syncfusion.com/ej2/material.css" rel="stylesheet"> -->
|
<!-- <link href="https://cdn.syncfusion.com/ej2/material.css" rel="stylesheet"> -->
|
||||||
<!-- <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" /> -->
|
<!-- <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" /> -->
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
export * from './TableStyle';
|
export * from './TableStyle';
|
||||||
|
|
||||||
|
export const Align = { Left: 'left', Right: 'right', Center: 'center' };
|
||||||
|
|||||||
@@ -1,3 +1 @@
|
|||||||
|
|
||||||
|
|
||||||
export * from './ButtonLink';
|
export * from './ButtonLink';
|
||||||
@@ -21,5 +21,5 @@ export const CommercialDocEntriesTable = styled(DataTable)`
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
export const CommercialDocFooter = styled.div`
|
export const CommercialDocFooter = styled.div`
|
||||||
margin-top: 25px;
|
margin-top: 28px;
|
||||||
`;
|
`;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
|
|
||||||
import { ButtonLink } from 'components';
|
import { ButtonLink } from '../Button';
|
||||||
import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
||||||
|
|
||||||
function CustomerDrawerLinkComponent({
|
function CustomerDrawerLinkComponent({
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ function TableHeaderCell({ column, index }) {
|
|||||||
<div
|
<div
|
||||||
{...column.getHeaderProps({
|
{...column.getHeaderProps({
|
||||||
className: classNames(column.className || '', 'th', {
|
className: classNames(column.className || '', 'th', {
|
||||||
'align-right': column.align === 'right',
|
[`align-${column.align}`]: column.align,
|
||||||
}),
|
}),
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
@@ -89,12 +89,14 @@ export default function TableHeader() {
|
|||||||
return (
|
return (
|
||||||
<ScrollSyncPane>
|
<ScrollSyncPane>
|
||||||
<div className="thead">
|
<div className="thead">
|
||||||
{headerGroups.map((headerGroup, index) => (
|
<div className={'thead-inner'}>
|
||||||
<TableHeaderGroup key={index} headerGroup={headerGroup} />
|
{headerGroups.map((headerGroup, index) => (
|
||||||
))}
|
<TableHeaderGroup key={index} headerGroup={headerGroup} />
|
||||||
<If condition={progressBarLoading}>
|
))}
|
||||||
<MaterialProgressBar />
|
<If condition={progressBarLoading}>
|
||||||
</If>
|
<MaterialProgressBar />
|
||||||
|
</If>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</ScrollSyncPane>
|
</ScrollSyncPane>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
|
import clsx from 'classnames';
|
||||||
import TableContext from './TableContext';
|
import TableContext from './TableContext';
|
||||||
import { Skeleton } from 'components';
|
import { Skeleton } from 'components';
|
||||||
|
|
||||||
@@ -8,7 +9,13 @@ function TableHeaderCell({ column }) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
{...column.getHeaderProps({
|
{...column.getHeaderProps({
|
||||||
className: 'th',
|
className: clsx(
|
||||||
|
'th',
|
||||||
|
{
|
||||||
|
[`align-${column.align}`]: column.align,
|
||||||
|
},
|
||||||
|
column.className,
|
||||||
|
),
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Skeleton minWidth={skeletonWidthMin} maxWidth={skeletonWidthMax} />
|
<Skeleton minWidth={skeletonWidthMin} maxWidth={skeletonWidthMax} />
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { useContext } from 'react';
|
import React, { useContext } from 'react';
|
||||||
|
import clsx from 'classnames';
|
||||||
import TableContext from './TableContext';
|
import TableContext from './TableContext';
|
||||||
import { Skeleton } from 'components';
|
import { Skeleton } from 'components';
|
||||||
|
|
||||||
@@ -11,7 +12,13 @@ function TableHeaderCell({ column }) {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
{...column.getHeaderProps({
|
{...column.getHeaderProps({
|
||||||
className: 'td',
|
className: clsx(
|
||||||
|
'td',
|
||||||
|
{
|
||||||
|
[`align-${column.align}`]: column.align,
|
||||||
|
},
|
||||||
|
column.className,
|
||||||
|
),
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Skeleton minWidth={skeletonWidthMin} maxWidth={skeletonWidthMax} />
|
<Skeleton minWidth={skeletonWidthMin} maxWidth={skeletonWidthMax} />
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ import ReconcileVendorCreditDialog from '../containers/Dialogs/ReconcileVendorCr
|
|||||||
import LockingTransactionsDialog from '../containers/Dialogs/LockingTransactionsDialog';
|
import LockingTransactionsDialog from '../containers/Dialogs/LockingTransactionsDialog';
|
||||||
import UnlockingTransactionsDialog from '../containers/Dialogs/UnlockingTransactionsDialog';
|
import UnlockingTransactionsDialog from '../containers/Dialogs/UnlockingTransactionsDialog';
|
||||||
import UnlockingPartialTransactionsDialog from '../containers/Dialogs/UnlockingPartialTransactionsDialog';
|
import UnlockingPartialTransactionsDialog from '../containers/Dialogs/UnlockingPartialTransactionsDialog';
|
||||||
|
import CreditNotePdfPreviewDialog from '../containers/Dialogs/CreditNotePdfPreviewDialog';
|
||||||
|
import PaymentReceivePdfPreviewDialog from '../containers/Dialogs/PaymentReceivePdfPreviewDialog';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Dialogs container.
|
* Dialogs container.
|
||||||
@@ -74,6 +76,8 @@ export default function DialogsContainer() {
|
|||||||
<UnlockingPartialTransactionsDialog
|
<UnlockingPartialTransactionsDialog
|
||||||
dialogName={'unlocking-partial-transactions'}
|
dialogName={'unlocking-partial-transactions'}
|
||||||
/>
|
/>
|
||||||
|
<CreditNotePdfPreviewDialog dialogName={'credit-note-pdf-preview'} />
|
||||||
|
<PaymentReceivePdfPreviewDialog dialogName={'payment-pdf-preview'} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
23
src/components/FinancialReport/index.js
Normal file
23
src/components/FinancialReport/index.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
const FinancialStatementRoot = styled.div``;
|
||||||
|
const FinancialStatementBodyRoot = styled.div``;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @returns {React.JSX}
|
||||||
|
*/
|
||||||
|
export function FinancialReport({ children, className }) {
|
||||||
|
return <FinancialStatementRoot children={children} className={className} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {React.JSX}
|
||||||
|
*/
|
||||||
|
export function FinancialReportBody({ children, className }) {
|
||||||
|
return (
|
||||||
|
<FinancialStatementBodyRoot children={children} className={className} />
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
import React, { useMemo, useCallback } from 'react';
|
|
||||||
import moment from 'moment';
|
|
||||||
import classnames from 'classnames';
|
|
||||||
import { FormattedMessage as T } from 'components';
|
|
||||||
import intl from 'react-intl-universal';
|
|
||||||
|
|
||||||
import 'style/pages/FinancialStatements/FinancialSheet.scss';
|
|
||||||
|
|
||||||
import { If, LoadingIndicator, MODIFIER } from 'components';
|
|
||||||
|
|
||||||
export default function FinancialSheet({
|
|
||||||
companyName,
|
|
||||||
sheetType,
|
|
||||||
fromDate,
|
|
||||||
toDate,
|
|
||||||
asDate,
|
|
||||||
children,
|
|
||||||
accountingBasis,
|
|
||||||
name,
|
|
||||||
loading,
|
|
||||||
className,
|
|
||||||
basis,
|
|
||||||
minimal = false,
|
|
||||||
fullWidth = false,
|
|
||||||
currentDate = true,
|
|
||||||
}) {
|
|
||||||
|
|
||||||
const format = 'DD MMMM YYYY';
|
|
||||||
const formattedFromDate = useMemo(() => moment(fromDate).format(format), [
|
|
||||||
fromDate,
|
|
||||||
]);
|
|
||||||
const formattedToDate = useMemo(() => moment(toDate).format(format), [
|
|
||||||
toDate,
|
|
||||||
]);
|
|
||||||
const formattedAsDate = useMemo(() => moment(asDate).format(format), [
|
|
||||||
asDate,
|
|
||||||
]);
|
|
||||||
|
|
||||||
const nameModifer = name ? `financial-sheet--${name}` : '';
|
|
||||||
const methodsLabels = useMemo(
|
|
||||||
() => ({
|
|
||||||
cash: intl.get('cash'),
|
|
||||||
accrual: intl.get('accrual'),
|
|
||||||
}),
|
|
||||||
[],
|
|
||||||
);
|
|
||||||
const getBasisLabel = useCallback((b) => methodsLabels[b], [methodsLabels]);
|
|
||||||
const basisLabel = useMemo(() => getBasisLabel(basis), [
|
|
||||||
getBasisLabel,
|
|
||||||
basis,
|
|
||||||
]);
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={classnames('financial-sheet', nameModifer, className, {
|
|
||||||
[MODIFIER.FINANCIAL_SHEET_MINIMAL]: minimal,
|
|
||||||
'is-full-width': fullWidth,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{loading ? (
|
|
||||||
<LoadingIndicator loading={loading} spinnerSize={34} />
|
|
||||||
) : (
|
|
||||||
<div className={classnames('financial-sheet__inner')}>
|
|
||||||
<If condition={!!companyName}>
|
|
||||||
<h1 class="financial-sheet__title">{companyName}</h1>
|
|
||||||
</If>
|
|
||||||
|
|
||||||
<If condition={!!sheetType}>
|
|
||||||
<h6 class="financial-sheet__sheet-type">{sheetType}</h6>
|
|
||||||
</If>
|
|
||||||
|
|
||||||
<div class="financial-sheet__date">
|
|
||||||
<If condition={asDate}>
|
|
||||||
<T id={'as'} /> {formattedAsDate}
|
|
||||||
</If>
|
|
||||||
|
|
||||||
<If condition={fromDate && toDate}>
|
|
||||||
<T id={'from'} /> {formattedFromDate} | <T id={'to'} />{' '}
|
|
||||||
{formattedToDate}
|
|
||||||
</If>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="financial-sheet__table">{children}</div>
|
|
||||||
<div class="financial-sheet__accounting-basis">{accountingBasis}</div>
|
|
||||||
|
|
||||||
<div class="financial-sheet__footer">
|
|
||||||
<If condition={basisLabel}>
|
|
||||||
<span class="financial-sheet__basis">
|
|
||||||
<T id={'accounting_basis'} /> {basisLabel}
|
|
||||||
</span>
|
|
||||||
</If>
|
|
||||||
|
|
||||||
<If condition={currentDate}>
|
|
||||||
<span class="financial-sheet__current-date">
|
|
||||||
{moment().format('YYYY MMM DD HH:MM')}
|
|
||||||
</span>
|
|
||||||
</If>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
101
src/components/FinancialSheet/FinancialSheet.js
Normal file
101
src/components/FinancialSheet/FinancialSheet.js
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
import React, { useMemo, useCallback } from 'react';
|
||||||
|
import moment from 'moment';
|
||||||
|
import intl from 'react-intl-universal';
|
||||||
|
|
||||||
|
import If from '../Utils/If';
|
||||||
|
import { FormattedMessage as T } from '../FormattedMessage';
|
||||||
|
import {
|
||||||
|
FinancialSheetRoot,
|
||||||
|
FinancialSheetFooterCurrentTime,
|
||||||
|
FinancialSheetFooterBasis,
|
||||||
|
FinancialSheetFooter,
|
||||||
|
FinancialSheetAccountingBasis,
|
||||||
|
FinancialSheetTable,
|
||||||
|
FinancialSheetDate,
|
||||||
|
FinancialSheetType,
|
||||||
|
FinancialSheetTitle,
|
||||||
|
} from './StyledFinancialSheet';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Financial sheet.
|
||||||
|
* @returns {React.JSX}
|
||||||
|
*/
|
||||||
|
export function FinancialSheet({
|
||||||
|
companyName,
|
||||||
|
sheetType,
|
||||||
|
fromDate,
|
||||||
|
toDate,
|
||||||
|
asDate,
|
||||||
|
children,
|
||||||
|
accountingBasis,
|
||||||
|
basis,
|
||||||
|
minimal = false,
|
||||||
|
fullWidth = false,
|
||||||
|
currentDate = true,
|
||||||
|
className,
|
||||||
|
}) {
|
||||||
|
const format = 'DD MMMM YYYY';
|
||||||
|
const formattedFromDate = useMemo(
|
||||||
|
() => moment(fromDate).format(format),
|
||||||
|
[fromDate],
|
||||||
|
);
|
||||||
|
const formattedToDate = useMemo(
|
||||||
|
() => moment(toDate).format(format),
|
||||||
|
[toDate],
|
||||||
|
);
|
||||||
|
const formattedAsDate = useMemo(
|
||||||
|
() => moment(asDate).format(format),
|
||||||
|
[asDate],
|
||||||
|
);
|
||||||
|
const methodsLabels = useMemo(
|
||||||
|
() => ({
|
||||||
|
cash: intl.get('cash'),
|
||||||
|
accrual: intl.get('accrual'),
|
||||||
|
}),
|
||||||
|
[],
|
||||||
|
);
|
||||||
|
const getBasisLabel = useCallback((b) => methodsLabels[b], [methodsLabels]);
|
||||||
|
const basisLabel = useMemo(
|
||||||
|
() => getBasisLabel(basis),
|
||||||
|
[getBasisLabel, basis],
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FinancialSheetRoot
|
||||||
|
minimal={minimal}
|
||||||
|
fullWidth={fullWidth}
|
||||||
|
className={className}
|
||||||
|
>
|
||||||
|
{companyName && <FinancialSheetTitle>{companyName}</FinancialSheetTitle>}
|
||||||
|
{sheetType && <FinancialSheetType>{sheetType}</FinancialSheetType>}
|
||||||
|
|
||||||
|
<FinancialSheetDate>
|
||||||
|
<If condition={asDate}>
|
||||||
|
<T id={'as'} /> {formattedAsDate}
|
||||||
|
</If>
|
||||||
|
<If condition={fromDate && toDate}>
|
||||||
|
<T id={'from'} /> {formattedFromDate} | <T id={'to'} />{' '}
|
||||||
|
{formattedToDate}
|
||||||
|
</If>
|
||||||
|
</FinancialSheetDate>
|
||||||
|
|
||||||
|
<FinancialSheetTable>{children}</FinancialSheetTable>
|
||||||
|
<FinancialSheetAccountingBasis>
|
||||||
|
{accountingBasis}
|
||||||
|
</FinancialSheetAccountingBasis>
|
||||||
|
|
||||||
|
<FinancialSheetFooter>
|
||||||
|
{basisLabel && (
|
||||||
|
<FinancialSheetFooterBasis>
|
||||||
|
<T id={'accounting_basis'} /> {basisLabel}
|
||||||
|
</FinancialSheetFooterBasis>
|
||||||
|
)}
|
||||||
|
{currentDate && (
|
||||||
|
<FinancialSheetFooterCurrentTime>
|
||||||
|
{moment().format('YYYY MMM DD HH:MM')}
|
||||||
|
</FinancialSheetFooterCurrentTime>
|
||||||
|
)}
|
||||||
|
</FinancialSheetFooter>
|
||||||
|
</FinancialSheetRoot>
|
||||||
|
);
|
||||||
|
}
|
||||||
85
src/components/FinancialSheet/FinancialSheetSkeleton.js
Normal file
85
src/components/FinancialSheet/FinancialSheetSkeleton.js
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
import { Align } from 'common';
|
||||||
|
import { SkeletonText } from 'components';
|
||||||
|
import DataTable from '../../components/DataTable'
|
||||||
|
|
||||||
|
import TableSkeletonRows from 'components/Datatable/TableSkeletonRows';
|
||||||
|
import TableSkeletonHeader from 'components/Datatable/TableHeaderSkeleton';
|
||||||
|
import { TableStyle } from 'common';
|
||||||
|
import {
|
||||||
|
FinancialSheetRoot,
|
||||||
|
FinancialSheetTitle,
|
||||||
|
FinancialSheetType,
|
||||||
|
FinancialSheetDate,
|
||||||
|
FinancialSheetTable,
|
||||||
|
} from './StyledFinancialSheet';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Financial sheet paper skeleton.
|
||||||
|
* @returns {React.JSX}
|
||||||
|
*/
|
||||||
|
export function FinancialSheetSkeleton({
|
||||||
|
minimal,
|
||||||
|
fullWidth,
|
||||||
|
titleCharsLength,
|
||||||
|
typeCharsLength,
|
||||||
|
dateCharsLength,
|
||||||
|
skeletonTableColumns,
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<FinancialSheetRoot minimal={minimal} fullWidth={fullWidth}>
|
||||||
|
<FinancialSheetTitle>
|
||||||
|
<SkeletonText charsLength={titleCharsLength} />
|
||||||
|
</FinancialSheetTitle>
|
||||||
|
|
||||||
|
<FinancialSheetType>
|
||||||
|
<SkeletonText charsLength={typeCharsLength} />
|
||||||
|
</FinancialSheetType>
|
||||||
|
|
||||||
|
<FinancialSheetDate>
|
||||||
|
<SkeletonText charsLength={dateCharsLength} />
|
||||||
|
</FinancialSheetDate>
|
||||||
|
|
||||||
|
<FinancialSheetTable>
|
||||||
|
<FinancialSkeletonTable
|
||||||
|
columns={skeletonTableColumns}
|
||||||
|
data={[]}
|
||||||
|
noInitialFetch={true}
|
||||||
|
expandable={true}
|
||||||
|
styleName={TableStyle.Constrant}
|
||||||
|
TableLoadingRenderer={TableSkeletonRows}
|
||||||
|
TableHeaderSkeletonRenderer={TableSkeletonHeader}
|
||||||
|
headerLoading={true}
|
||||||
|
loading={true}
|
||||||
|
/>
|
||||||
|
</FinancialSheetTable>
|
||||||
|
</FinancialSheetRoot>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
FinancialSheetSkeleton.defaultProps = {
|
||||||
|
titleCharsLength: 20,
|
||||||
|
typeCharsLength: 40,
|
||||||
|
dateCharsLength: 20,
|
||||||
|
skeletonTableColumns: [
|
||||||
|
{
|
||||||
|
id: 'skeleton-1',
|
||||||
|
className: 'skeleton-1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
id: 'skeleton-2',
|
||||||
|
className: 'skeleton-2',
|
||||||
|
align: Align.Right,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
};
|
||||||
|
|
||||||
|
const FinancialSkeletonTable = styled(DataTable)`
|
||||||
|
.table .th .skeleton,
|
||||||
|
.table .td .skeleton {
|
||||||
|
margin-top: 4px;
|
||||||
|
margin-bottom: 4px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
9
src/components/FinancialSheet/ReportDataTable.js
Normal file
9
src/components/FinancialSheet/ReportDataTable.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
import DataTable from '../DataTable';
|
||||||
|
|
||||||
|
export const ReportDataTable = styled(DataTable)`
|
||||||
|
.table .tbody .tr.no-results:last-of-type .td {
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
`;
|
||||||
82
src/components/FinancialSheet/StyledFinancialSheet.js
Normal file
82
src/components/FinancialSheet/StyledFinancialSheet.js
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
export const FinancialSheetRoot = styled.div`
|
||||||
|
border: 2px solid #f0f0f0;
|
||||||
|
border-radius: 10px;
|
||||||
|
min-width: 640px;
|
||||||
|
width: auto;
|
||||||
|
padding: 30px 18px;
|
||||||
|
max-width: 100%;
|
||||||
|
margin: 35px auto;
|
||||||
|
min-height: 400px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
background: #fff;
|
||||||
|
|
||||||
|
${(props) =>
|
||||||
|
props.fullWidth &&
|
||||||
|
`
|
||||||
|
width: 100%;
|
||||||
|
margin-top: 25px;`}
|
||||||
|
|
||||||
|
${(props) =>
|
||||||
|
props.minimal &&
|
||||||
|
`
|
||||||
|
border: 0;
|
||||||
|
padding: 0;
|
||||||
|
margin-top: 20px;
|
||||||
|
|
||||||
|
${FinancialSheetTitle} {
|
||||||
|
font-size: 18px;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
${FinancialSheetTitle} + ${FinancialSheetDate} {
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
${FinancialSheetDate} {
|
||||||
|
margin-top: 20px;
|
||||||
|
}
|
||||||
|
`}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const FinancialSheetTitle = styled.h1`
|
||||||
|
margin: 0;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 20px;
|
||||||
|
color: #464646;
|
||||||
|
text-align: center;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const FinancialSheetType = styled.h6`
|
||||||
|
text-align: center;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 400;
|
||||||
|
color: #666;
|
||||||
|
margin-top: 6px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const FinancialSheetDate = styled.div`
|
||||||
|
text-align: center;
|
||||||
|
color: #666;
|
||||||
|
margin-top: 6px;
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const FinancialSheetFooter = styled.div`
|
||||||
|
color: #888;
|
||||||
|
text-align: center;
|
||||||
|
margin-top: auto;
|
||||||
|
padding-top: 18px;
|
||||||
|
font-size: 13px;
|
||||||
|
|
||||||
|
> span + span {
|
||||||
|
padding-left: 10px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
export const FinancialSheetTable = styled.div`
|
||||||
|
margin-top: 24px;
|
||||||
|
`;
|
||||||
|
export const FinancialSheetFooterBasis = styled.span``;
|
||||||
|
export const FinancialSheetFooterCurrentTime = styled.span``;
|
||||||
|
|
||||||
|
export const FinancialSheetAccountingBasis = styled.div``;
|
||||||
3
src/components/FinancialSheet/index.js
Normal file
3
src/components/FinancialSheet/index.js
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
export * from './FinancialSheet';
|
||||||
|
export * from './FinancialSheetSkeleton';
|
||||||
|
export * from './ReportDataTable';
|
||||||
@@ -1,15 +1,24 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import className from 'classnames';
|
import styled from 'styled-components';
|
||||||
import 'style/containers/FinancialStatements/FinancialSheet.scss';
|
|
||||||
|
|
||||||
export default function FinancialStatements({ name, children }) {
|
const FinancialStatementRoot = styled.div``;
|
||||||
|
const FinancialStatementBodyRoot = styled.div``;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} param0
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
export function FinancialStatement({ children, className }) {
|
||||||
|
return <FinancialStatementRoot children={children} className={className} />;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {React.JSX}
|
||||||
|
*/
|
||||||
|
export function FinancialStatementBody({ children, className }) {
|
||||||
return (
|
return (
|
||||||
<div
|
<FinancialStatementBodyRoot children={children} className={className} />
|
||||||
className={className('financial-statement', {
|
|
||||||
[`financial-statement--${name}`]: name,
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export default function Sidebar({ dashboardContentRef }) {
|
|||||||
* @returns {React.JSX}
|
* @returns {React.JSX}
|
||||||
*/
|
*/
|
||||||
function SidebarFooterVersion() {
|
function SidebarFooterVersion() {
|
||||||
const { REACT_APP_VERSION: VERSION } = process.env;
|
const { VERSION } = process.env;
|
||||||
|
|
||||||
if (!VERSION) {
|
if (!VERSION) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -6,14 +6,36 @@ import { randomNumber } from 'utils';
|
|||||||
/**
|
/**
|
||||||
* Skeleton component.
|
* Skeleton component.
|
||||||
*/
|
*/
|
||||||
export default function Skeleton({
|
export function Skeleton({
|
||||||
Tag = 'span',
|
Tag = 'span',
|
||||||
minWidth = 40,
|
minWidth = 40,
|
||||||
maxWidth = 100,
|
maxWidth = 100,
|
||||||
|
children,
|
||||||
}) {
|
}) {
|
||||||
const randomWidth = useMemo(() => randomNumber(minWidth, maxWidth), [
|
const randomWidth = useMemo(
|
||||||
minWidth,
|
() => randomNumber(minWidth, maxWidth),
|
||||||
maxWidth,
|
[minWidth, maxWidth],
|
||||||
]);
|
);
|
||||||
return <Tag className={'skeleton'} style={{ width: `${randomWidth}%` }} />;
|
return (
|
||||||
|
<Tag
|
||||||
|
className={'skeleton'}
|
||||||
|
style={{ width: `${randomWidth}%` }}
|
||||||
|
children={children}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function SkeletonText({
|
||||||
|
Tag = 'span',
|
||||||
|
charsLength,
|
||||||
|
minChars = 40,
|
||||||
|
maxChars = 100,
|
||||||
|
}) {
|
||||||
|
const computedCharLength = useMemo(
|
||||||
|
() => (charsLength ? charsLength : randomNumber(minChars, maxChars)),
|
||||||
|
[charsLength, minChars, maxChars],
|
||||||
|
);
|
||||||
|
const randamText = 'X'.repeat(computedCharLength);
|
||||||
|
|
||||||
|
return <Tag className={'skeleton'}>{randamText}</Tag>;
|
||||||
}
|
}
|
||||||
|
|||||||
0
src/components/SkeletonText.js
Normal file
0
src/components/SkeletonText.js
Normal file
@@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
|
|
||||||
import { ButtonLink } from 'components';
|
import { ButtonLink } from '../Button';
|
||||||
import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
import withDrawerActions from 'containers/Drawer/withDrawerActions';
|
||||||
|
|
||||||
function VendorDrawerLinkComponent({
|
function VendorDrawerLinkComponent({
|
||||||
|
|||||||
@@ -5,9 +5,6 @@ import Choose from './Utils/Choose';
|
|||||||
import For from './Utils/For';
|
import For from './Utils/For';
|
||||||
import { FormattedMessage, FormattedHTMLMessage } from './FormattedMessage';
|
import { FormattedMessage, FormattedHTMLMessage } from './FormattedMessage';
|
||||||
import ListSelect from './ListSelect';
|
import ListSelect from './ListSelect';
|
||||||
import FinancialStatement from './FinancialStatement';
|
|
||||||
// import DynamicFilterValueField from './DynamicFilter/DynamicFilterValueField';
|
|
||||||
// import DynamicFilterCompatatorField from './DynamicFilter/DynamicFilterCompatatorField';
|
|
||||||
import ErrorMessage from './ErrorMessage';
|
import ErrorMessage from './ErrorMessage';
|
||||||
import MODIFIER from './modifiers';
|
import MODIFIER from './modifiers';
|
||||||
import FieldHint from './FieldHint';
|
import FieldHint from './FieldHint';
|
||||||
@@ -41,7 +38,6 @@ import InputPrependText from './Forms/InputPrependText';
|
|||||||
import PageFormBigNumber from './PageFormBigNumber';
|
import PageFormBigNumber from './PageFormBigNumber';
|
||||||
import AccountsMultiSelect from './AccountsMultiSelect';
|
import AccountsMultiSelect from './AccountsMultiSelect';
|
||||||
import ContactsMultiSelect from './ContactsMultiSelect';
|
import ContactsMultiSelect from './ContactsMultiSelect';
|
||||||
import Skeleton from './Skeleton';
|
|
||||||
import ContextMenu from './ContextMenu';
|
import ContextMenu from './ContextMenu';
|
||||||
import TableFastCell from './Datatable/TableFastCell';
|
import TableFastCell from './Datatable/TableFastCell';
|
||||||
import DashboardContentTable from './Dashboard/DashboardContentTable';
|
import DashboardContentTable from './Dashboard/DashboardContentTable';
|
||||||
@@ -95,6 +91,10 @@ export * from './Card';
|
|||||||
export * from './Customers'
|
export * from './Customers'
|
||||||
export * from './Vendors'
|
export * from './Vendors'
|
||||||
export * from './Table';
|
export * from './Table';
|
||||||
|
export * from './Skeleton';
|
||||||
|
export * from './FinancialStatement';
|
||||||
|
export * from './FinancialReport';
|
||||||
|
export * from './FinancialSheet';
|
||||||
|
|
||||||
const Hint = FieldHint;
|
const Hint = FieldHint;
|
||||||
|
|
||||||
@@ -110,7 +110,6 @@ export {
|
|||||||
T,
|
T,
|
||||||
Money,
|
Money,
|
||||||
ListSelect,
|
ListSelect,
|
||||||
FinancialStatement,
|
|
||||||
// DynamicFilterValueField,
|
// DynamicFilterValueField,
|
||||||
// DynamicFilterCompatatorField,
|
// DynamicFilterCompatatorField,
|
||||||
MODIFIER,
|
MODIFIER,
|
||||||
@@ -148,7 +147,6 @@ export {
|
|||||||
DataTableEditable,
|
DataTableEditable,
|
||||||
ContactsMultiSelect,
|
ContactsMultiSelect,
|
||||||
TableFastCell,
|
TableFastCell,
|
||||||
Skeleton,
|
|
||||||
ContextMenu,
|
ContextMenu,
|
||||||
DashboardContentTable,
|
DashboardContentTable,
|
||||||
DashboardPageContent,
|
DashboardPageContent,
|
||||||
|
|||||||
@@ -70,6 +70,20 @@ export const financialReportMenus = [
|
|||||||
subject: AbilitySubject.Report,
|
subject: AbilitySubject.Report,
|
||||||
ability: ReportsAction.READ_AP_AGING_SUMMARY,
|
ability: ReportsAction.READ_AP_AGING_SUMMARY,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
title: <T id={'report.balance_sheet_comparison.title'} />,
|
||||||
|
desc: <T id={'report.balance_sheet_comparison.desc'} />,
|
||||||
|
link: 'financial-reports/balance-sheet?previousYear=true&previousYearAmountChange=true&previousYearPercentageChange=true',
|
||||||
|
subject: AbilitySubject.Report,
|
||||||
|
ability: ReportsAction.READ_BALANCE_SHEET,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: <T id={'report.profit_loss_sheet_comparison.title'} />,
|
||||||
|
desc: <T id={'report.profit_loss_sheet_comparison.desc'} />,
|
||||||
|
link: '/financial-reports/profit-loss-sheet?previousYear=true&previousYearAmountChange=true&previousYearPercentageChange=true',
|
||||||
|
subject: AbilitySubject.Report,
|
||||||
|
ability: ReportsAction.READ_PROFIT_LOSS,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|||||||
67
src/containers/Alerts/Customers/CustomerActivateAlert.js
Normal file
67
src/containers/Alerts/Customers/CustomerActivateAlert.js
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { FormattedMessage as T } from 'components';
|
||||||
|
import intl from 'react-intl-universal';
|
||||||
|
import { Intent, Alert } from '@blueprintjs/core';
|
||||||
|
import { AppToaster } from 'components';
|
||||||
|
|
||||||
|
import { useActivateContact } from 'hooks/query';
|
||||||
|
|
||||||
|
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
|
||||||
|
import withAlertActions from 'containers/Alert/withAlertActions';
|
||||||
|
|
||||||
|
import { compose } from 'utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customer activate alert.
|
||||||
|
*/
|
||||||
|
function CustomerActivateAlert({
|
||||||
|
name,
|
||||||
|
|
||||||
|
// #withAlertStoreConnect
|
||||||
|
isOpen,
|
||||||
|
payload: { customerId, service },
|
||||||
|
|
||||||
|
// #withAlertActions
|
||||||
|
closeAlert,
|
||||||
|
}) {
|
||||||
|
const { mutateAsync: activateContact, isLoading } = useActivateContact();
|
||||||
|
|
||||||
|
// Handle activate constomer alert cancel.
|
||||||
|
const handleCancelActivateCustomer = () => {
|
||||||
|
closeAlert(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle confirm customer activated.
|
||||||
|
const handleConfirmCustomerActivate = () => {
|
||||||
|
activateContact(customerId)
|
||||||
|
.then(() => {
|
||||||
|
AppToaster.show({
|
||||||
|
message: intl.get('customer.alert.activated_message'),
|
||||||
|
intent: Intent.SUCCESS,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {})
|
||||||
|
.finally(() => {
|
||||||
|
closeAlert(name);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Alert
|
||||||
|
cancelButtonText={<T id={'cancel'} />}
|
||||||
|
confirmButtonText={<T id={'activate'} />}
|
||||||
|
intent={Intent.WARNING}
|
||||||
|
isOpen={isOpen}
|
||||||
|
onCancel={handleCancelActivateCustomer}
|
||||||
|
loading={isLoading}
|
||||||
|
onConfirm={handleConfirmCustomerActivate}
|
||||||
|
>
|
||||||
|
<p>{intl.get('customer.alert.are_you_sure_want_to_activate_this_customer')}</p>
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
withAlertStoreConnect(),
|
||||||
|
withAlertActions,
|
||||||
|
)(CustomerActivateAlert);
|
||||||
69
src/containers/Alerts/Customers/CustomerInactivateAlert.js
Normal file
69
src/containers/Alerts/Customers/CustomerInactivateAlert.js
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { FormattedMessage as T } from 'components';
|
||||||
|
import intl from 'react-intl-universal';
|
||||||
|
import { Intent, Alert } from '@blueprintjs/core';
|
||||||
|
import { AppToaster } from 'components';
|
||||||
|
|
||||||
|
import { useInactivateContact } from 'hooks/query';
|
||||||
|
|
||||||
|
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
|
||||||
|
import withAlertActions from 'containers/Alert/withAlertActions';
|
||||||
|
|
||||||
|
import { compose } from 'utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* customer inactivate alert.
|
||||||
|
*/
|
||||||
|
function CustomerInactivateAlert({
|
||||||
|
name,
|
||||||
|
// #withAlertStoreConnect
|
||||||
|
isOpen,
|
||||||
|
payload: { customerId, service },
|
||||||
|
|
||||||
|
// #withAlertActions
|
||||||
|
closeAlert,
|
||||||
|
}) {
|
||||||
|
const { mutateAsync: inactivateContact, isLoading } = useInactivateContact();
|
||||||
|
|
||||||
|
// Handle cancel inactivate alert.
|
||||||
|
const handleCancelInactivateCustomer = () => {
|
||||||
|
closeAlert(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle confirm contact Inactive.
|
||||||
|
const handleConfirmCustomerInactive = () => {
|
||||||
|
inactivateContact(customerId)
|
||||||
|
.then(() => {
|
||||||
|
AppToaster.show({
|
||||||
|
message: intl.get('the_contact_has_been_inactivated_successfully'),
|
||||||
|
intent: Intent.SUCCESS,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {})
|
||||||
|
.finally(() => {
|
||||||
|
closeAlert(name);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Alert
|
||||||
|
cancelButtonText={<T id={'cancel'} />}
|
||||||
|
confirmButtonText={<T id={'inactivate'} />}
|
||||||
|
intent={Intent.WARNING}
|
||||||
|
isOpen={isOpen}
|
||||||
|
onCancel={handleCancelInactivateCustomer}
|
||||||
|
onConfirm={handleConfirmCustomerInactive}
|
||||||
|
loading={isLoading}
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
{intl.get(
|
||||||
|
'customer.alert.are_you_sure_want_to_inactivate_this_customer',
|
||||||
|
)}
|
||||||
|
</p>
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
export default compose(
|
||||||
|
withAlertStoreConnect(),
|
||||||
|
withAlertActions,
|
||||||
|
)(CustomerInactivateAlert);
|
||||||
69
src/containers/Alerts/Vendors/VendorActivateAlert.js
Normal file
69
src/containers/Alerts/Vendors/VendorActivateAlert.js
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { FormattedMessage as T } from 'components';
|
||||||
|
import intl from 'react-intl-universal';
|
||||||
|
import { Intent, Alert } from '@blueprintjs/core';
|
||||||
|
import { AppToaster } from 'components';
|
||||||
|
|
||||||
|
import { useActivateContact } from 'hooks/query';
|
||||||
|
|
||||||
|
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
|
||||||
|
import withAlertActions from 'containers/Alert/withAlertActions';
|
||||||
|
|
||||||
|
import { compose } from 'utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vendor activate alert.
|
||||||
|
*/
|
||||||
|
function VendorActivateAlert({
|
||||||
|
name,
|
||||||
|
|
||||||
|
// #withAlertStoreConnect
|
||||||
|
isOpen,
|
||||||
|
payload: { vendorId },
|
||||||
|
|
||||||
|
// #withAlertActions
|
||||||
|
closeAlert,
|
||||||
|
}) {
|
||||||
|
const { mutateAsync: activateContact, isLoading } = useActivateContact();
|
||||||
|
|
||||||
|
// Handle activate vendor alert cancel.
|
||||||
|
const handleCancelActivateVendor = () => {
|
||||||
|
closeAlert(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle confirm vendor activated.
|
||||||
|
const handleConfirmVendorActivate = () => {
|
||||||
|
activateContact(vendorId)
|
||||||
|
.then(() => {
|
||||||
|
AppToaster.show({
|
||||||
|
message: intl.get('vendor.alert.activated_message'),
|
||||||
|
intent: Intent.SUCCESS,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {})
|
||||||
|
.finally(() => {
|
||||||
|
closeAlert(name);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Alert
|
||||||
|
cancelButtonText={<T id={'cancel'} />}
|
||||||
|
confirmButtonText={<T id={'activate'} />}
|
||||||
|
intent={Intent.WARNING}
|
||||||
|
isOpen={isOpen}
|
||||||
|
onCancel={handleCancelActivateVendor}
|
||||||
|
loading={isLoading}
|
||||||
|
onConfirm={handleConfirmVendorActivate}
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
{intl.get('vendor.alert.are_you_sure_want_to_activate_this_vendor')}
|
||||||
|
</p>
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
withAlertStoreConnect(),
|
||||||
|
withAlertActions,
|
||||||
|
)(VendorActivateAlert);
|
||||||
68
src/containers/Alerts/Vendors/VendorInactivateAlert.js
Normal file
68
src/containers/Alerts/Vendors/VendorInactivateAlert.js
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { FormattedMessage as T } from 'components';
|
||||||
|
import intl from 'react-intl-universal';
|
||||||
|
import { Intent, Alert } from '@blueprintjs/core';
|
||||||
|
import { AppToaster } from 'components';
|
||||||
|
|
||||||
|
import { useInactivateContact } from 'hooks/query';
|
||||||
|
|
||||||
|
import withAlertStoreConnect from 'containers/Alert/withAlertStoreConnect';
|
||||||
|
import withAlertActions from 'containers/Alert/withAlertActions';
|
||||||
|
|
||||||
|
import { compose } from 'utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vendor inactivate alert.
|
||||||
|
*/
|
||||||
|
function VendorInactivateAlert({
|
||||||
|
name,
|
||||||
|
// #withAlertStoreConnect
|
||||||
|
isOpen,
|
||||||
|
payload: { vendorId },
|
||||||
|
|
||||||
|
// #withAlertActions
|
||||||
|
closeAlert,
|
||||||
|
}) {
|
||||||
|
const { mutateAsync: inactivateContact, isLoading } = useInactivateContact();
|
||||||
|
|
||||||
|
// Handle cancel inactivate alert.
|
||||||
|
const handleCancelInactivateVendor = () => {
|
||||||
|
closeAlert(name);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Handle confirm contact Inactive.
|
||||||
|
const handleConfirmVendorInactive = () => {
|
||||||
|
inactivateContact(vendorId)
|
||||||
|
.then(() => {
|
||||||
|
AppToaster.show({
|
||||||
|
message: intl.get('vendor.alert.inactivated_message'),
|
||||||
|
intent: Intent.SUCCESS,
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((error) => {})
|
||||||
|
.finally(() => {
|
||||||
|
closeAlert(name);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Alert
|
||||||
|
cancelButtonText={<T id={'cancel'} />}
|
||||||
|
confirmButtonText={<T id={'inactivate'} />}
|
||||||
|
intent={Intent.WARNING}
|
||||||
|
isOpen={isOpen}
|
||||||
|
onCancel={handleCancelInactivateVendor}
|
||||||
|
onConfirm={handleConfirmVendorInactive}
|
||||||
|
loading={isLoading}
|
||||||
|
>
|
||||||
|
<p>
|
||||||
|
{intl.get('vendor.alert.are_you_sure_want_to_inactivate_this_vendor')}
|
||||||
|
</p>
|
||||||
|
</Alert>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(
|
||||||
|
withAlertStoreConnect(),
|
||||||
|
withAlertActions,
|
||||||
|
)(VendorInactivateAlert);
|
||||||
@@ -3,11 +3,11 @@ import React from 'react';
|
|||||||
const CustomerDeleteAlert = React.lazy(() =>
|
const CustomerDeleteAlert = React.lazy(() =>
|
||||||
import('../Alerts/Customers/CustomerDeleteAlert'),
|
import('../Alerts/Customers/CustomerDeleteAlert'),
|
||||||
);
|
);
|
||||||
const ContactActivateAlert = React.lazy(() =>
|
const CustomerActivateAlert = React.lazy(() =>
|
||||||
import('../Alerts/Contacts/ContactActivateAlert'),
|
import('../Alerts/Customers/CustomerActivateAlert'),
|
||||||
);
|
);
|
||||||
const ContactInactivateAlert = React.lazy(() =>
|
const CustomerInactivateAlert = React.lazy(() =>
|
||||||
import('../Alerts/Contacts/ContactInactivateAlert'),
|
import('../Alerts/Customers/CustomerInactivateAlert'),
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -15,6 +15,6 @@ const ContactInactivateAlert = React.lazy(() =>
|
|||||||
*/
|
*/
|
||||||
export default [
|
export default [
|
||||||
{ name: 'customer-delete', component: CustomerDeleteAlert },
|
{ name: 'customer-delete', component: CustomerDeleteAlert },
|
||||||
{ name: 'contact-activate', component: ContactActivateAlert },
|
{ name: 'customer-activate', component: CustomerActivateAlert },
|
||||||
{ name: 'contact-inactivate', component: ContactInactivateAlert },
|
{ name: 'customer-inactivate', component: CustomerInactivateAlert },
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -89,15 +89,17 @@ function CustomersTable({
|
|||||||
|
|
||||||
// Handle cancel/confirm inactive.
|
// Handle cancel/confirm inactive.
|
||||||
const handleInactiveCustomer = ({ id, contact_service }) => {
|
const handleInactiveCustomer = ({ id, contact_service }) => {
|
||||||
openAlert('contact-inactivate', {
|
openAlert('customer-inactivate', {
|
||||||
contactId: id,
|
customerId: id,
|
||||||
service: contact_service,
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle cancel/confirm activate.
|
// Handle cancel/confirm activate.
|
||||||
const handleActivateCustomer = ({ id, contact_service }) => {
|
const handleActivateCustomer = ({ id, contact_service }) => {
|
||||||
openAlert('contact-activate', { contactId: id, service: contact_service });
|
openAlert('customer-activate', {
|
||||||
|
customerId: id,
|
||||||
|
service: contact_service,
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle view detail contact.
|
// Handle view detail contact.
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import { Menu, MenuItem, MenuDivider, Intent } from '@blueprintjs/core';
|
import {
|
||||||
|
Menu,
|
||||||
|
MenuItem,
|
||||||
|
MenuDivider,
|
||||||
|
Intent,
|
||||||
|
Tooltip,
|
||||||
|
Position,
|
||||||
|
Classes,
|
||||||
|
} from '@blueprintjs/core';
|
||||||
import clsx from 'classnames';
|
import clsx from 'classnames';
|
||||||
|
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
@@ -79,7 +87,7 @@ export function ActionsMenu({
|
|||||||
* Phone number accessor.
|
* Phone number accessor.
|
||||||
*/
|
*/
|
||||||
export function PhoneNumberAccessor(row) {
|
export function PhoneNumberAccessor(row) {
|
||||||
return <div className={'work_phone'}>{row.work_phone}</div>;
|
return <div className={'work_phone'}>{row.personal_phone}</div>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,6 +97,24 @@ export function BalanceAccessor(row) {
|
|||||||
return <Money amount={row.closing_balance} currency={row.currency_code} />;
|
return <Money amount={row.closing_balance} currency={row.currency_code} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Note column accessor.
|
||||||
|
*/
|
||||||
|
export function NoteAccessor(row) {
|
||||||
|
return (
|
||||||
|
<If condition={row.note}>
|
||||||
|
<Tooltip
|
||||||
|
className={Classes.TOOLTIP_INDICATOR}
|
||||||
|
content={row.note}
|
||||||
|
position={Position.LEFT_TOP}
|
||||||
|
hoverOpenDelay={50}
|
||||||
|
>
|
||||||
|
<Icon icon={'file-alt'} iconSize={16} />
|
||||||
|
</Tooltip>
|
||||||
|
</If>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve customers table columns.
|
* Retrieve customers table columns.
|
||||||
*/
|
*/
|
||||||
@@ -123,12 +149,20 @@ export function useCustomersTableColumns() {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'work_phone',
|
id: 'work_phone',
|
||||||
Header: intl.get('work_phone'),
|
Header: intl.get('phone_number'),
|
||||||
accessor: PhoneNumberAccessor,
|
accessor: PhoneNumberAccessor,
|
||||||
className: 'phone_number',
|
className: 'phone_number',
|
||||||
width: 100,
|
width: 100,
|
||||||
clickable: true,
|
clickable: true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
id: 'note',
|
||||||
|
Header: intl.get('note'),
|
||||||
|
accessor: NoteAccessor,
|
||||||
|
disableSortBy: true,
|
||||||
|
width: 85,
|
||||||
|
clickable: true,
|
||||||
|
},
|
||||||
{
|
{
|
||||||
id: 'balance',
|
id: 'balance',
|
||||||
Header: intl.get('receivable_balance'),
|
Header: intl.get('receivable_balance'),
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { AnchorButton } from '@blueprintjs/core';
|
||||||
|
|
||||||
|
import { DialogContent, PdfDocumentPreview, T } from 'components';
|
||||||
|
import { usePdfCreditNote } from 'hooks/query';
|
||||||
|
|
||||||
|
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||||
|
import { compose } from 'utils';
|
||||||
|
|
||||||
|
function CreditNotePdfPreviewDialogContent({
|
||||||
|
subscriptionForm: { creditNoteId },
|
||||||
|
}) {
|
||||||
|
const { isLoading, pdfUrl } = usePdfCreditNote(creditNoteId);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DialogContent>
|
||||||
|
<div class="dialog__header-actions">
|
||||||
|
<AnchorButton
|
||||||
|
href={pdfUrl}
|
||||||
|
target={'__blank'}
|
||||||
|
minimal={true}
|
||||||
|
outlined={true}
|
||||||
|
>
|
||||||
|
<T id={'pdf_preview.preview.button'} />
|
||||||
|
</AnchorButton>
|
||||||
|
|
||||||
|
<AnchorButton
|
||||||
|
href={pdfUrl}
|
||||||
|
download={'creditNote.pdf'}
|
||||||
|
minimal={true}
|
||||||
|
outlined={true}
|
||||||
|
>
|
||||||
|
<T id={'pdf_preview.download.button'} />
|
||||||
|
</AnchorButton>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<PdfDocumentPreview
|
||||||
|
height={760}
|
||||||
|
width={1000}
|
||||||
|
isLoading={isLoading}
|
||||||
|
url={pdfUrl}
|
||||||
|
/>
|
||||||
|
</DialogContent>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(withDialogActions)(CreditNotePdfPreviewDialogContent);
|
||||||
42
src/containers/Dialogs/CreditNotePdfPreviewDialog/index.js
Normal file
42
src/containers/Dialogs/CreditNotePdfPreviewDialog/index.js
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import { T, Dialog, DialogSuspense } from 'components';
|
||||||
|
|
||||||
|
import withDialogRedux from 'components/DialogReduxConnect';
|
||||||
|
|
||||||
|
import { CLASSES } from 'common/classes';
|
||||||
|
import { compose } from 'utils';
|
||||||
|
|
||||||
|
const PdfPreviewDialogContent = React.lazy(() =>
|
||||||
|
import('./CreditNotePdfPreviewDialogContent'),
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credit note PDF previwe dialog.
|
||||||
|
*/
|
||||||
|
function CreditNotePdfPreviewDialog({
|
||||||
|
dialogName,
|
||||||
|
payload = { creditNoteId: null },
|
||||||
|
isOpen,
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
name={dialogName}
|
||||||
|
title={<T id={'credit_note_preview.dialog.title'} />}
|
||||||
|
className={classNames(CLASSES.DIALOG_PDF_PREVIEW)}
|
||||||
|
autoFocus={true}
|
||||||
|
canEscapeKeyClose={true}
|
||||||
|
isOpen={isOpen}
|
||||||
|
style={{ width: '1000px' }}
|
||||||
|
>
|
||||||
|
<DialogSuspense>
|
||||||
|
<PdfPreviewDialogContent
|
||||||
|
dialogName={dialogName}
|
||||||
|
subscriptionForm={payload}
|
||||||
|
/>
|
||||||
|
</DialogSuspense>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
export default compose(withDialogRedux())(CreditNotePdfPreviewDialog);
|
||||||
@@ -29,7 +29,7 @@ const defaultInitialValues = {
|
|||||||
cashflow_account_id: '',
|
cashflow_account_id: '',
|
||||||
credit_account_id: '',
|
credit_account_id: '',
|
||||||
description: '',
|
description: '',
|
||||||
published: '',
|
publish: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
function MoneyInForm({
|
function MoneyInForm({
|
||||||
@@ -73,7 +73,7 @@ function MoneyInForm({
|
|||||||
const handleFormSubmit = (values, { setSubmitting, setErrors }) => {
|
const handleFormSubmit = (values, { setSubmitting, setErrors }) => {
|
||||||
const form = {
|
const form = {
|
||||||
...omit(values, ['currency_code']),
|
...omit(values, ['currency_code']),
|
||||||
published: submitPayload.publish,
|
publish: true,
|
||||||
};
|
};
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
createCashflowTransactionMutate(form)
|
createCashflowTransactionMutate(form)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const Schema = Yup.object().shape({
|
|||||||
.min(3)
|
.min(3)
|
||||||
.max(DATATYPES_LENGTH.TEXT)
|
.max(DATATYPES_LENGTH.TEXT)
|
||||||
.label(intl.get('description')),
|
.label(intl.get('description')),
|
||||||
published: Yup.boolean(),
|
publish: Yup.boolean(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const CreateMoneyInFormSchema = Schema;
|
export const CreateMoneyInFormSchema = Schema;
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ const defaultInitialValues = {
|
|||||||
cashflow_account_id: '',
|
cashflow_account_id: '',
|
||||||
credit_account_id: '',
|
credit_account_id: '',
|
||||||
description: '',
|
description: '',
|
||||||
published: '',
|
publish: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
function MoneyOutForm({
|
function MoneyOutForm({
|
||||||
@@ -73,7 +73,7 @@ function MoneyOutForm({
|
|||||||
const handleFormSubmit = (values, { setSubmitting, setErrors }) => {
|
const handleFormSubmit = (values, { setSubmitting, setErrors }) => {
|
||||||
const form = {
|
const form = {
|
||||||
...omit(values, ['currency_code']),
|
...omit(values, ['currency_code']),
|
||||||
published: submitPayload.publish,
|
publish: true,
|
||||||
};
|
};
|
||||||
setSubmitting(true);
|
setSubmitting(true);
|
||||||
createCashflowTransactionMutate(form)
|
createCashflowTransactionMutate(form)
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ const Schema = Yup.object().shape({
|
|||||||
.min(3)
|
.min(3)
|
||||||
.max(DATATYPES_LENGTH.TEXT)
|
.max(DATATYPES_LENGTH.TEXT)
|
||||||
.label(intl.get('description')),
|
.label(intl.get('description')),
|
||||||
published: Yup.boolean(),
|
publish: Yup.boolean(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const CreateMoneyOutSchema = Schema;
|
export const CreateMoneyOutSchema = Schema;
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { AnchorButton } from '@blueprintjs/core';
|
||||||
|
|
||||||
|
import { DialogContent, PdfDocumentPreview, T } from 'components';
|
||||||
|
import { usePdfPaymentReceive } from 'hooks/query';
|
||||||
|
|
||||||
|
import withDialogActions from 'containers/Dialog/withDialogActions';
|
||||||
|
import { compose } from 'utils';
|
||||||
|
|
||||||
|
function PaymentReceivePdfPreviewDialogContent({
|
||||||
|
subscriptionForm: { paymentReceiveId },
|
||||||
|
}) {
|
||||||
|
const { isLoading, pdfUrl } = usePdfPaymentReceive(paymentReceiveId);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DialogContent>
|
||||||
|
<div class="dialog__header-actions">
|
||||||
|
<AnchorButton
|
||||||
|
href={pdfUrl}
|
||||||
|
target={'__blank'}
|
||||||
|
minimal={true}
|
||||||
|
outlined={true}
|
||||||
|
>
|
||||||
|
<T id={'pdf_preview.preview.button'} />
|
||||||
|
</AnchorButton>
|
||||||
|
|
||||||
|
<AnchorButton
|
||||||
|
href={pdfUrl}
|
||||||
|
download={'payment.pdf'}
|
||||||
|
minimal={true}
|
||||||
|
outlined={true}
|
||||||
|
>
|
||||||
|
<T id={'pdf_preview.download.button'} />
|
||||||
|
</AnchorButton>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<PdfDocumentPreview
|
||||||
|
height={760}
|
||||||
|
width={1000}
|
||||||
|
isLoading={isLoading}
|
||||||
|
url={pdfUrl}
|
||||||
|
/>
|
||||||
|
</DialogContent>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(withDialogActions)(
|
||||||
|
PaymentReceivePdfPreviewDialogContent,
|
||||||
|
);
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import { T, Dialog, DialogSuspense } from 'components';
|
||||||
|
|
||||||
|
import withDialogRedux from 'components/DialogReduxConnect';
|
||||||
|
|
||||||
|
import { CLASSES } from 'common/classes';
|
||||||
|
import { compose } from 'utils';
|
||||||
|
|
||||||
|
// Lazy loading the content.
|
||||||
|
const PdfPreviewDialogContent = React.lazy(() =>
|
||||||
|
import('./PaymentReceivePdfPreviewContent'),
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Payment receive PDF preview dialog.
|
||||||
|
*/
|
||||||
|
function PaymentReceivePdfPreviewDialog({
|
||||||
|
dialogName,
|
||||||
|
payload = { paymentReceiveId: null },
|
||||||
|
isOpen,
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Dialog
|
||||||
|
name={dialogName}
|
||||||
|
title={<T id={'payment_receive_preview.dialog.title'} />}
|
||||||
|
className={classNames(CLASSES.DIALOG_PDF_PREVIEW)}
|
||||||
|
autoFocus={true}
|
||||||
|
canEscapeKeyClose={true}
|
||||||
|
isOpen={isOpen}
|
||||||
|
style={{ width: '1000px' }}
|
||||||
|
>
|
||||||
|
<DialogSuspense>
|
||||||
|
<PdfPreviewDialogContent
|
||||||
|
dialogName={dialogName}
|
||||||
|
subscriptionForm={payload}
|
||||||
|
/>
|
||||||
|
</DialogSuspense>
|
||||||
|
</Dialog>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default compose(withDialogRedux())(PaymentReceivePdfPreviewDialog);
|
||||||
@@ -65,6 +65,11 @@ function CreditNoteDetailActionsBar({
|
|||||||
openDialog('reconcile-credit-note', { creditNoteId });
|
openDialog('reconcile-credit-note', { creditNoteId });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handle print credit note.
|
||||||
|
const handlePrintCreditNote = () => {
|
||||||
|
openDialog('credit-note-pdf-preview', { creditNoteId });
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DrawerActionsBar>
|
<DrawerActionsBar>
|
||||||
<NavbarGroup>
|
<NavbarGroup>
|
||||||
@@ -88,6 +93,14 @@ function CreditNoteDetailActionsBar({
|
|||||||
<NavbarDivider />
|
<NavbarDivider />
|
||||||
</If>
|
</If>
|
||||||
</Can>
|
</Can>
|
||||||
|
<Can I={CreditNoteAction.View} a={AbilitySubject.CreditNote}>
|
||||||
|
<Button
|
||||||
|
className={Classes.MINIMAL}
|
||||||
|
icon={<Icon icon="print-16" />}
|
||||||
|
text={<T id={'print'} />}
|
||||||
|
onClick={handlePrintCreditNote}
|
||||||
|
/>
|
||||||
|
</Can>
|
||||||
<Can I={CreditNoteAction.Delete} a={AbilitySubject.CreditNote}>
|
<Can I={CreditNoteAction.Delete} a={AbilitySubject.CreditNote}>
|
||||||
<Button
|
<Button
|
||||||
className={Classes.MINIMAL}
|
className={Classes.MINIMAL}
|
||||||
|
|||||||
@@ -15,9 +15,14 @@ import { useCreditNoteDetailDrawerContext } from './CreditNoteDetailDrawerProvid
|
|||||||
*/
|
*/
|
||||||
export default function CreditNoteDetailFooter() {
|
export default function CreditNoteDetailFooter() {
|
||||||
const { creditNote } = useCreditNoteDetailDrawerContext();
|
const { creditNote } = useCreditNoteDetailDrawerContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CommercialDocFooter>
|
<CommercialDocFooter>
|
||||||
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
|
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
|
||||||
|
<If condition={creditNote.terms_conditions}>
|
||||||
|
<DetailItem label={<T id={'note'} />} children={creditNote.note} />
|
||||||
|
</If>
|
||||||
|
|
||||||
<If condition={creditNote.terms_conditions}>
|
<If condition={creditNote.terms_conditions}>
|
||||||
<DetailItem label={<T id={'terms_conditions'} />}>
|
<DetailItem label={<T id={'terms_conditions'} />}>
|
||||||
{creditNote.terms_conditions}
|
{creditNote.terms_conditions}
|
||||||
|
|||||||
@@ -42,6 +42,12 @@ export default function CreditNoteDetailHeader() {
|
|||||||
<Row>
|
<Row>
|
||||||
<Col xs={6}>
|
<Col xs={6}>
|
||||||
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
|
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
|
||||||
|
<DetailItem
|
||||||
|
label={intl.get('credit_note.drawer.label_credit_note_date')}
|
||||||
|
>
|
||||||
|
<FormatDate value={creditNote.formatted_credit_note_date} />
|
||||||
|
</DetailItem>
|
||||||
|
|
||||||
<DetailItem
|
<DetailItem
|
||||||
label={intl.get('credit_note.drawer.label_credit_note_no')}
|
label={intl.get('credit_note.drawer.label_credit_note_no')}
|
||||||
>
|
>
|
||||||
@@ -53,12 +59,6 @@ export default function CreditNoteDetailHeader() {
|
|||||||
{creditNote.customer?.display_name}
|
{creditNote.customer?.display_name}
|
||||||
</CustomerDrawerLink>
|
</CustomerDrawerLink>
|
||||||
</DetailItem>
|
</DetailItem>
|
||||||
|
|
||||||
<DetailItem
|
|
||||||
label={intl.get('credit_note.drawer.label_credit_note_date')}
|
|
||||||
>
|
|
||||||
<FormatDate value={creditNote.formatted_credit_note_date} />
|
|
||||||
</DetailItem>
|
|
||||||
</DetailsMenu>
|
</DetailsMenu>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
@@ -77,11 +77,6 @@ export default function CreditNoteDetailHeader() {
|
|||||||
label={intl.get('reference')}
|
label={intl.get('reference')}
|
||||||
children={defaultTo(creditNote.reference_no, '-')}
|
children={defaultTo(creditNote.reference_no, '-')}
|
||||||
/>
|
/>
|
||||||
<DetailItem
|
|
||||||
label={intl.get('note')}
|
|
||||||
children={defaultTo(creditNote.note, '-')}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<DetailItem
|
<DetailItem
|
||||||
label={<T id={'credit_note.drawer.label_created_at'} />}
|
label={<T id={'credit_note.drawer.label_created_at'} />}
|
||||||
children={<FormatDate value={creditNote.created_at} />}
|
children={<FormatDate value={creditNote.created_at} />}
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ import {
|
|||||||
DetailItem,
|
DetailItem,
|
||||||
Row,
|
Row,
|
||||||
Col,
|
Col,
|
||||||
ButtonLink,
|
|
||||||
CustomerDrawerLink,
|
CustomerDrawerLink,
|
||||||
} from 'components';
|
} from 'components';
|
||||||
import { useEstimateDetailDrawerContext } from './EstimateDetailDrawerProvider';
|
import { useEstimateDetailDrawerContext } from './EstimateDetailDrawerProvider';
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ function BillPaymentTransactions({
|
|||||||
}}
|
}}
|
||||||
styleName={TableStyle.Constrant}
|
styleName={TableStyle.Constrant}
|
||||||
TableLoadingRenderer={TableSkeletonRows}
|
TableLoadingRenderer={TableSkeletonRows}
|
||||||
|
sticky={true}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ function EstimatePaymentTransactions({
|
|||||||
}}
|
}}
|
||||||
styleName={TableStyle.Constrant}
|
styleName={TableStyle.Constrant}
|
||||||
TableLoadingRenderer={TableSkeletonRows}
|
TableLoadingRenderer={TableSkeletonRows}
|
||||||
|
sticky={true}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -68,6 +68,7 @@ function InvoicePaymentTransactions({
|
|||||||
}}
|
}}
|
||||||
styleName={TableStyle.Constrant}
|
styleName={TableStyle.Constrant}
|
||||||
TableLoadingRenderer={TableSkeletonRows}
|
TableLoadingRenderer={TableSkeletonRows}
|
||||||
|
sticky={true}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -66,6 +66,7 @@ function ReceiptPaymentTransactions({
|
|||||||
}}
|
}}
|
||||||
styleName={TableStyle.Constrant}
|
styleName={TableStyle.Constrant}
|
||||||
TableLoadingRenderer={TableSkeletonRows}
|
TableLoadingRenderer={TableSkeletonRows}
|
||||||
|
sticky={true}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,42 +1,29 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
T,
|
T,
|
||||||
TotalLines,
|
CommercialDocFooter,
|
||||||
TotalLine,
|
DetailsMenu,
|
||||||
TotalLineBorderStyle,
|
If,
|
||||||
TotalLineTextStyle,
|
DetailItem,
|
||||||
} from 'components';
|
} from 'components';
|
||||||
import { usePaymentMadeDetailContext } from './PaymentMadeDetailProvider';
|
import { usePaymentMadeDetailContext } from './PaymentMadeDetailProvider';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Payment made - Details panel - Footer.
|
* Payment made - Details panel - Footer.
|
||||||
*/
|
*/
|
||||||
export default function PaymentMadeDetailFooter() {
|
export function PaymentMadeDetailFooter() {
|
||||||
const { paymentMade } = usePaymentMadeDetailContext();
|
const { paymentMade } = usePaymentMadeDetailContext();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PaymentMadeFooterRoot>
|
<CommercialDocFooter>
|
||||||
<PaymentMadeTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
|
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
|
||||||
<TotalLine
|
<If condition={paymentMade.statement}>
|
||||||
title={<T id={'payment_made.details.subtotal'} />}
|
<DetailItem label={<T id={'payment_made.details.statement'} />}>
|
||||||
value={paymentMade.amount}
|
{paymentMade.statement}
|
||||||
borderStyle={TotalLineBorderStyle.SingleDark}
|
</DetailItem>
|
||||||
/>
|
</If>
|
||||||
<TotalLine
|
</DetailsMenu>
|
||||||
title={<T id={'payment_made.details.total'} />}
|
</CommercialDocFooter>
|
||||||
value={paymentMade.formatted_amount}
|
|
||||||
borderStyle={TotalLineBorderStyle.DoubleDark}
|
|
||||||
textStyle={TotalLineTextStyle.Bold}
|
|
||||||
/>
|
|
||||||
</PaymentMadeTotalLines>
|
|
||||||
</PaymentMadeFooterRoot>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const PaymentMadeFooterRoot = styled.div``;
|
|
||||||
|
|
||||||
export const PaymentMadeTotalLines = styled(TotalLines)`
|
|
||||||
margin-left: auto;
|
|
||||||
`;
|
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ export default function PaymentMadeDetailHeader() {
|
|||||||
<Row>
|
<Row>
|
||||||
<Col xs={6}>
|
<Col xs={6}>
|
||||||
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
|
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
|
||||||
|
<DetailItem
|
||||||
|
label={intl.get('payment_date')}
|
||||||
|
children={<FormatDate value={paymentMade.payment_date} />}
|
||||||
|
/>
|
||||||
<DetailItem
|
<DetailItem
|
||||||
label={intl.get('payment_made.details.payment_number')}
|
label={intl.get('payment_made.details.payment_number')}
|
||||||
children={defaultTo(paymentMade.payment_number, '-')}
|
children={defaultTo(paymentMade.payment_number, '-')}
|
||||||
@@ -47,11 +51,6 @@ export default function PaymentMadeDetailHeader() {
|
|||||||
label={intl.get('payment_account')}
|
label={intl.get('payment_account')}
|
||||||
children={paymentMade.payment_account?.name}
|
children={paymentMade.payment_account?.name}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<DetailItem
|
|
||||||
label={intl.get('payment_date')}
|
|
||||||
children={<FormatDate value={paymentMade.payment_date} />}
|
|
||||||
/>
|
|
||||||
</DetailsMenu>
|
</DetailsMenu>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={6}>
|
<Col xs={6}>
|
||||||
@@ -61,8 +60,8 @@ export default function PaymentMadeDetailHeader() {
|
|||||||
minLabelSize={'180px'}
|
minLabelSize={'180px'}
|
||||||
>
|
>
|
||||||
<DetailItem
|
<DetailItem
|
||||||
label={intl.get('description')}
|
label={intl.get('reference')}
|
||||||
children={defaultTo(paymentMade.statement, '-')}
|
children={defaultTo(paymentMade.reference, '-')}
|
||||||
/>
|
/>
|
||||||
<DetailItem
|
<DetailItem
|
||||||
label={intl.get('created_at')}
|
label={intl.get('created_at')}
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ function PaymentMadeDetailProvider({ paymentMadeId, ...props }) {
|
|||||||
enabled: !!paymentMadeId,
|
enabled: !!paymentMadeId,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
// Provider state.
|
||||||
//provider.
|
|
||||||
const provider = {
|
const provider = {
|
||||||
paymentMadeId,
|
paymentMadeId,
|
||||||
paymentMade,
|
paymentMade,
|
||||||
|
|||||||
@@ -4,7 +4,8 @@ import { CommercialDocBox } from 'components';
|
|||||||
|
|
||||||
import PaymentMadeDetailHeader from './PaymentMadeDetailHeader';
|
import PaymentMadeDetailHeader from './PaymentMadeDetailHeader';
|
||||||
import PaymentMadeDetailTable from './PaymentMadeDetailTable';
|
import PaymentMadeDetailTable from './PaymentMadeDetailTable';
|
||||||
import PaymentMadeDetailFooter from './PaymentMadeDetailFooter';
|
import PaymentMadeDetailTableFooter from './PaymentMadeDetailTableFooter';
|
||||||
|
import { PaymentMadeDetailFooter } from './PaymentMadeDetailFooter';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Payment made detail tab.
|
* Payment made detail tab.
|
||||||
@@ -15,6 +16,7 @@ export default function PaymentMadeDetailTab() {
|
|||||||
<CommercialDocBox>
|
<CommercialDocBox>
|
||||||
<PaymentMadeDetailHeader />
|
<PaymentMadeDetailHeader />
|
||||||
<PaymentMadeDetailTable />
|
<PaymentMadeDetailTable />
|
||||||
|
<PaymentMadeDetailTableFooter />
|
||||||
<PaymentMadeDetailFooter />
|
<PaymentMadeDetailFooter />
|
||||||
</CommercialDocBox>
|
</CommercialDocBox>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
import {
|
||||||
|
T,
|
||||||
|
TotalLines,
|
||||||
|
TotalLine,
|
||||||
|
TotalLineBorderStyle,
|
||||||
|
TotalLineTextStyle,
|
||||||
|
} from 'components';
|
||||||
|
import { usePaymentMadeDetailContext } from './PaymentMadeDetailProvider';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Payment made - Details panel - Footer.
|
||||||
|
*/
|
||||||
|
export default function PaymentMadeDetailTableFooter() {
|
||||||
|
const { paymentMade } = usePaymentMadeDetailContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PaymentMadeFooterRoot>
|
||||||
|
<PaymentMadeTotalLines labelColWidth={'180px'} amountColWidth={'180px'}>
|
||||||
|
<TotalLine
|
||||||
|
title={<T id={'payment_made.details.subtotal'} />}
|
||||||
|
value={paymentMade.amount}
|
||||||
|
borderStyle={TotalLineBorderStyle.SingleDark}
|
||||||
|
/>
|
||||||
|
<TotalLine
|
||||||
|
title={<T id={'payment_made.details.total'} />}
|
||||||
|
value={paymentMade.formatted_amount}
|
||||||
|
borderStyle={TotalLineBorderStyle.DoubleDark}
|
||||||
|
textStyle={TotalLineTextStyle.Bold}
|
||||||
|
/>
|
||||||
|
</PaymentMadeTotalLines>
|
||||||
|
</PaymentMadeFooterRoot>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const PaymentMadeFooterRoot = styled.div``;
|
||||||
|
|
||||||
|
export const PaymentMadeTotalLines = styled(TotalLines)`
|
||||||
|
margin-left: auto;
|
||||||
|
`;
|
||||||
@@ -62,6 +62,11 @@ function PaymentReceiveActionsBar({
|
|||||||
openDialog('notify-payment-via-sms', { paymentReceiveId });
|
openDialog('notify-payment-via-sms', { paymentReceiveId });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Handle print payment receive.
|
||||||
|
const handlePrintPaymentReceive = () => {
|
||||||
|
openDialog('payment-pdf-preview', { paymentReceiveId });
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DrawerActionsBar>
|
<DrawerActionsBar>
|
||||||
<NavbarGroup>
|
<NavbarGroup>
|
||||||
@@ -74,6 +79,14 @@ function PaymentReceiveActionsBar({
|
|||||||
/>
|
/>
|
||||||
<NavbarDivider />
|
<NavbarDivider />
|
||||||
</Can>
|
</Can>
|
||||||
|
<Can I={PaymentReceiveAction.View} a={AbilitySubject.PaymentReceive}>
|
||||||
|
<Button
|
||||||
|
className={Classes.MINIMAL}
|
||||||
|
icon={<Icon icon="print-16" />}
|
||||||
|
text={<T id={'print'} />}
|
||||||
|
onClick={handlePrintPaymentReceive}
|
||||||
|
/>
|
||||||
|
</Can>
|
||||||
<Can I={PaymentReceiveAction.Delete} a={AbilitySubject.PaymentReceive}>
|
<Can I={PaymentReceiveAction.Delete} a={AbilitySubject.PaymentReceive}>
|
||||||
<Button
|
<Button
|
||||||
className={Classes.MINIMAL}
|
className={Classes.MINIMAL}
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import {
|
|||||||
DetailItem,
|
DetailItem,
|
||||||
CommercialDocHeader,
|
CommercialDocHeader,
|
||||||
CommercialDocTopHeader,
|
CommercialDocTopHeader,
|
||||||
ButtonLink,
|
|
||||||
CustomerDrawerLink,
|
CustomerDrawerLink,
|
||||||
} from 'components';
|
} from 'components';
|
||||||
import { usePaymentReceiveDetailContext } from './PaymentReceiveDetailProvider';
|
import { usePaymentReceiveDetailContext } from './PaymentReceiveDetailProvider';
|
||||||
@@ -34,6 +33,10 @@ export default function PaymentReceiveDetailHeader() {
|
|||||||
<Row>
|
<Row>
|
||||||
<Col xs={6}>
|
<Col xs={6}>
|
||||||
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
|
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
|
||||||
|
<DetailItem
|
||||||
|
label={intl.get('payment_date')}
|
||||||
|
children={<FormatDate value={paymentReceive.payment_date} />}
|
||||||
|
/>
|
||||||
<DetailItem
|
<DetailItem
|
||||||
label={intl.get('payment_receive.details.payment_number')}
|
label={intl.get('payment_receive.details.payment_number')}
|
||||||
children={defaultTo(paymentReceive.payment_receive_no, '-')}
|
children={defaultTo(paymentReceive.payment_receive_no, '-')}
|
||||||
@@ -48,10 +51,6 @@ export default function PaymentReceiveDetailHeader() {
|
|||||||
label={intl.get('deposit_account')}
|
label={intl.get('deposit_account')}
|
||||||
children={paymentReceive.deposit_account?.name}
|
children={paymentReceive.deposit_account?.name}
|
||||||
/>
|
/>
|
||||||
<DetailItem
|
|
||||||
label={intl.get('payment_date')}
|
|
||||||
children={<FormatDate value={paymentReceive.payment_date} />}
|
|
||||||
/>
|
|
||||||
</DetailsMenu>
|
</DetailsMenu>
|
||||||
</Col>
|
</Col>
|
||||||
|
|
||||||
@@ -62,8 +61,8 @@ export default function PaymentReceiveDetailHeader() {
|
|||||||
minLabelSize={'180px'}
|
minLabelSize={'180px'}
|
||||||
>
|
>
|
||||||
<DetailItem
|
<DetailItem
|
||||||
label={intl.get('description')}
|
label={intl.get('reference')}
|
||||||
children={defaultTo(paymentReceive.statement, '—')}
|
children={defaultTo(paymentReceive.reference_no, '-')}
|
||||||
/>
|
/>
|
||||||
<DetailItem
|
<DetailItem
|
||||||
label={intl.get('created_at')}
|
label={intl.get('created_at')}
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import {
|
||||||
|
CommercialDocFooter,
|
||||||
|
T,
|
||||||
|
If,
|
||||||
|
DetailsMenu,
|
||||||
|
DetailItem,
|
||||||
|
} from '../../../components';
|
||||||
|
import { useVendorCreditDetailDrawerContext } from './VendorCreditDetailDrawerProvider';
|
||||||
|
|
||||||
|
export function VendorCreditDetailFooter() {
|
||||||
|
const { vendorCredit } = useVendorCreditDetailDrawerContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CommercialDocFooter>
|
||||||
|
<DetailsMenu direction={'horizantal'} minLabelSize={'150px'}>
|
||||||
|
<If condition={vendorCredit.note}>
|
||||||
|
<DetailItem label={<T id={'note'} />} children={vendorCredit.note} />
|
||||||
|
</If>
|
||||||
|
</DetailsMenu>
|
||||||
|
</CommercialDocFooter>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -38,6 +38,11 @@ export default function VendorCreditDetailHeader() {
|
|||||||
<Row>
|
<Row>
|
||||||
<Col xs={6}>
|
<Col xs={6}>
|
||||||
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
|
<DetailsMenu direction={'horizantal'} minLabelSize={'180px'}>
|
||||||
|
<DetailItem
|
||||||
|
label={intl.get('vendor_credit.drawer.label_vendor_credit_date')}
|
||||||
|
>
|
||||||
|
<FormatDate value={vendorCredit.formatted_vendor_credit_date} />
|
||||||
|
</DetailItem>
|
||||||
<DetailItem
|
<DetailItem
|
||||||
label={intl.get('vendor_credit.drawer.label_vendor_credit_no')}
|
label={intl.get('vendor_credit.drawer.label_vendor_credit_no')}
|
||||||
>
|
>
|
||||||
@@ -49,12 +54,6 @@ export default function VendorCreditDetailHeader() {
|
|||||||
{vendorCredit.vendor?.display_name}
|
{vendorCredit.vendor?.display_name}
|
||||||
</VendorDrawerLink>
|
</VendorDrawerLink>
|
||||||
</DetailItem>
|
</DetailItem>
|
||||||
|
|
||||||
<DetailItem
|
|
||||||
label={intl.get('vendor_credit.drawer.label_vendor_credit_date')}
|
|
||||||
>
|
|
||||||
<FormatDate value={vendorCredit.formatted_vendor_credit_date} />
|
|
||||||
</DetailItem>
|
|
||||||
</DetailsMenu>
|
</DetailsMenu>
|
||||||
</Col>
|
</Col>
|
||||||
<Col xs={6}>
|
<Col xs={6}>
|
||||||
@@ -72,10 +71,6 @@ export default function VendorCreditDetailHeader() {
|
|||||||
label={intl.get('reference')}
|
label={intl.get('reference')}
|
||||||
children={defaultTo(vendorCredit.reference_no, '-')}
|
children={defaultTo(vendorCredit.reference_no, '-')}
|
||||||
/>
|
/>
|
||||||
<DetailItem
|
|
||||||
label={intl.get('note')}
|
|
||||||
children={defaultTo(vendorCredit.note, '-')}
|
|
||||||
/>
|
|
||||||
<DetailItem
|
<DetailItem
|
||||||
label={<T id={'vendor_credit.drawer.label_created_at'} />}
|
label={<T id={'vendor_credit.drawer.label_created_at'} />}
|
||||||
children={<FormatDate value={vendorCredit.created_at} />}
|
children={<FormatDate value={vendorCredit.created_at} />}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { CommercialDocBox } from 'components';
|
|||||||
import VendorCreditDetailHeader from './VendorCreditDetailHeader';
|
import VendorCreditDetailHeader from './VendorCreditDetailHeader';
|
||||||
import VendorCreditDetailTable from './VendorCreditDetailTable';
|
import VendorCreditDetailTable from './VendorCreditDetailTable';
|
||||||
import VendorCreditDetailDrawerFooter from './VendorCreditDetailDrawerFooter';
|
import VendorCreditDetailDrawerFooter from './VendorCreditDetailDrawerFooter';
|
||||||
|
import { VendorCreditDetailFooter } from './VendorCreditDetailFooter';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Vendor credit details panel.
|
* Vendor credit details panel.
|
||||||
@@ -16,6 +17,7 @@ export default function VendorCreditDetailPanel() {
|
|||||||
<VendorCreditDetailHeader />
|
<VendorCreditDetailHeader />
|
||||||
<VendorCreditDetailTable />
|
<VendorCreditDetailTable />
|
||||||
<VendorCreditDetailDrawerFooter />
|
<VendorCreditDetailDrawerFooter />
|
||||||
|
<VendorCreditDetailFooter />
|
||||||
</CommercialDocBox>
|
</CommercialDocBox>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import React, { useState, useCallback, useEffect } from 'react';
|
import React, { useState, useCallback, useEffect } from 'react';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import 'style/pages/FinancialStatements/APAgingSummary.scss';
|
import { getDefaultAPAgingSummaryQuery } from './common';
|
||||||
|
|
||||||
import { FinancialStatement } from 'components';
|
import { FinancialStatement } from 'components';
|
||||||
|
|
||||||
import APAgingSummaryHeader from './APAgingSummaryHeader';
|
import APAgingSummaryHeader from './APAgingSummaryHeader';
|
||||||
import APAgingSummaryActionsBar from './APAgingSummaryActionsBar';
|
import APAgingSummaryActionsBar from './APAgingSummaryActionsBar';
|
||||||
import APAgingSummaryTable from './APAgingSummaryTable';
|
import { APAgingSummaryBody } from './APAgingSummaryBody';
|
||||||
|
|
||||||
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||||
import { APAgingSummaryProvider } from './APAgingSummaryProvider';
|
import { APAgingSummaryProvider } from './APAgingSummaryProvider';
|
||||||
import { APAgingSummarySheetLoadingBar } from './components';
|
import { APAgingSummarySheetLoadingBar } from './components';
|
||||||
|
|
||||||
import withCurrentOrganization from '../../Organization/withCurrentOrganization';
|
|
||||||
import withAPAgingSummaryActions from './withAPAgingSummaryActions';
|
import withAPAgingSummaryActions from './withAPAgingSummaryActions';
|
||||||
|
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -27,11 +27,7 @@ function APAgingSummary({
|
|||||||
toggleAPAgingSummaryFilterDrawer: toggleDisplayFilterDrawer,
|
toggleAPAgingSummaryFilterDrawer: toggleDisplayFilterDrawer,
|
||||||
}) {
|
}) {
|
||||||
const [filter, setFilter] = useState({
|
const [filter, setFilter] = useState({
|
||||||
asDate: moment().endOf('day').format('YYYY-MM-DD'),
|
...getDefaultAPAgingSummaryQuery(),
|
||||||
agingDaysBefore: 30,
|
|
||||||
agingPeriods: 3,
|
|
||||||
vendorsIds: [],
|
|
||||||
filterByOption: 'without-zero-balance',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle filter submit.
|
// Handle filter submit.
|
||||||
@@ -50,7 +46,6 @@ function APAgingSummary({
|
|||||||
numberFormat,
|
numberFormat,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Hide the report filter drawer once the page unmount.
|
// Hide the report filter drawer once the page unmount.
|
||||||
useEffect(
|
useEffect(
|
||||||
() => () => {
|
() => () => {
|
||||||
@@ -73,18 +68,11 @@ function APAgingSummary({
|
|||||||
pageFilter={filter}
|
pageFilter={filter}
|
||||||
onSubmitFilter={handleFilterSubmit}
|
onSubmitFilter={handleFilterSubmit}
|
||||||
/>
|
/>
|
||||||
<div className={'financial-statement__body'}>
|
<APAgingSummaryBody organizationName={organizationName} />
|
||||||
<APAgingSummaryTable organizationName={organizationName} />
|
|
||||||
</div>
|
|
||||||
</FinancialStatement>
|
</FinancialStatement>
|
||||||
</DashboardPageContent>
|
</DashboardPageContent>
|
||||||
</APAgingSummaryProvider>
|
</APAgingSummaryProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default compose(
|
export default compose(withAPAgingSummaryActions)(APAgingSummary);
|
||||||
withCurrentOrganization(({ organization }) => ({
|
|
||||||
organizationName: organization?.name,
|
|
||||||
})),
|
|
||||||
withAPAgingSummaryActions,
|
|
||||||
)(APAgingSummary);
|
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import * as R from 'ramda';
|
||||||
|
|
||||||
|
import { FinancialReportBody } from '../FinancialReportPage';
|
||||||
|
import APAgingSummaryTable from './APAgingSummaryTable';
|
||||||
|
import { FinancialSheetSkeleton } from '../../../components/FinancialSheet';
|
||||||
|
|
||||||
|
import withCurrentOrganization from '../../Organization/withCurrentOrganization';
|
||||||
|
|
||||||
|
import { useAPAgingSummaryContext } from './APAgingSummaryProvider';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AP aging summary body.
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
*/
|
||||||
|
function APAgingSummaryBodyJSX({
|
||||||
|
// #withCurrentOrganization
|
||||||
|
organizationName,
|
||||||
|
}) {
|
||||||
|
const { isLoading } = useAPAgingSummaryContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FinancialReportBody>
|
||||||
|
{isLoading ? (
|
||||||
|
<FinancialSheetSkeleton />
|
||||||
|
) : (
|
||||||
|
<APAgingSummaryTable organizationName={organizationName} />
|
||||||
|
)}
|
||||||
|
</FinancialReportBody>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const APAgingSummaryBody = R.compose(
|
||||||
|
withCurrentOrganization(({ organization }) => ({
|
||||||
|
organizationName: organization?.name,
|
||||||
|
})),
|
||||||
|
)(APAgingSummaryBodyJSX);
|
||||||
@@ -4,6 +4,7 @@ import { Formik, Form } from 'formik';
|
|||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { Tabs, Tab, Button, Intent } from '@blueprintjs/core';
|
import { Tabs, Tab, Button, Intent } from '@blueprintjs/core';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import FinancialStatementHeader from 'containers/FinancialStatements/FinancialStatementHeader';
|
import FinancialStatementHeader from 'containers/FinancialStatements/FinancialStatementHeader';
|
||||||
import APAgingSummaryHeaderGeneral from './APAgingSummaryHeaderGeneral';
|
import APAgingSummaryHeaderGeneral from './APAgingSummaryHeaderGeneral';
|
||||||
@@ -11,8 +12,8 @@ import APAgingSummaryHeaderGeneral from './APAgingSummaryHeaderGeneral';
|
|||||||
import withAPAgingSummary from './withAPAgingSummary';
|
import withAPAgingSummary from './withAPAgingSummary';
|
||||||
import withAPAgingSummaryActions from './withAPAgingSummaryActions';
|
import withAPAgingSummaryActions from './withAPAgingSummaryActions';
|
||||||
|
|
||||||
import { compose } from 'utils';
|
|
||||||
import { transformToForm } from '../../../utils';
|
import { transformToForm } from '../../../utils';
|
||||||
|
import { compose } from 'utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AP Aging Summary Report - Drawer Header.
|
* AP Aging Summary Report - Drawer Header.
|
||||||
@@ -72,7 +73,7 @@ function APAgingSummaryHeader({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FinancialStatementHeader
|
<APAgingDrawerHeader
|
||||||
isOpen={isFilterDrawerOpen}
|
isOpen={isFilterDrawerOpen}
|
||||||
drawerProps={{ onClose: handleDrawerClose }}
|
drawerProps={{ onClose: handleDrawerClose }}
|
||||||
>
|
>
|
||||||
@@ -99,7 +100,7 @@ function APAgingSummaryHeader({
|
|||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
</Formik>
|
</Formik>
|
||||||
</FinancialStatementHeader>
|
</APAgingDrawerHeader>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,3 +110,9 @@ export default compose(
|
|||||||
isFilterDrawerOpen: APAgingSummaryFilterDrawer,
|
isFilterDrawerOpen: APAgingSummaryFilterDrawer,
|
||||||
})),
|
})),
|
||||||
)(APAgingSummaryHeader);
|
)(APAgingSummaryHeader);
|
||||||
|
|
||||||
|
const APAgingDrawerHeader = styled(FinancialStatementHeader)`
|
||||||
|
.bp3-drawer {
|
||||||
|
max-height: 520px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|||||||
@@ -1,12 +1,15 @@
|
|||||||
import React, { useCallback } from 'react';
|
import React from 'react';
|
||||||
import { FormattedMessage as T } from 'components';
|
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import { DataTable } from 'components';
|
import styled from 'styled-components';
|
||||||
import FinancialSheet from 'components/FinancialSheet';
|
|
||||||
|
import { ReportDataTable, FinancialSheet } from 'components';
|
||||||
|
import { TableStyle } from 'common';
|
||||||
|
|
||||||
import { useAPAgingSummaryContext } from './APAgingSummaryProvider';
|
import { useAPAgingSummaryContext } from './APAgingSummaryProvider';
|
||||||
import { useAPAgingSummaryColumns } from './components';
|
import { useAPAgingSummaryColumns } from './components';
|
||||||
|
|
||||||
|
import { tableRowTypesToClassnames } from 'utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AP aging summary table sheet.
|
* AP aging summary table sheet.
|
||||||
*/
|
*/
|
||||||
@@ -14,8 +17,6 @@ export default function APAgingSummaryTable({
|
|||||||
//#ownProps
|
//#ownProps
|
||||||
organizationName,
|
organizationName,
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
|
|
||||||
// AP aging summary report content.
|
// AP aging summary report content.
|
||||||
const {
|
const {
|
||||||
APAgingSummary: { tableRows },
|
APAgingSummary: { tableRows },
|
||||||
@@ -25,24 +26,33 @@ export default function APAgingSummaryTable({
|
|||||||
// AP aging summary columns.
|
// AP aging summary columns.
|
||||||
const columns = useAPAgingSummaryColumns();
|
const columns = useAPAgingSummaryColumns();
|
||||||
|
|
||||||
const rowClassNames = (row) => [`row-type--${row.original.rowType}`];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FinancialSheet
|
<FinancialSheet
|
||||||
companyName={organizationName}
|
companyName={organizationName}
|
||||||
name={'payable-aging-summary'}
|
|
||||||
sheetType={intl.get('payable_aging_summary')}
|
sheetType={intl.get('payable_aging_summary')}
|
||||||
asDate={new Date()}
|
asDate={new Date()}
|
||||||
loading={isAPAgingLoading}
|
loading={isAPAgingLoading}
|
||||||
>
|
>
|
||||||
<DataTable
|
<APAgingSummaryDataTable
|
||||||
className={'bigcapital-datatable--financial-report'}
|
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={tableRows}
|
data={tableRows}
|
||||||
rowClassNames={rowClassNames}
|
rowClassNames={tableRowTypesToClassnames}
|
||||||
noInitialFetch={true}
|
noInitialFetch={true}
|
||||||
sticky={true}
|
sticky={true}
|
||||||
|
styleName={TableStyle.Constrant}
|
||||||
/>
|
/>
|
||||||
</FinancialSheet>
|
</FinancialSheet>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const APAgingSummaryDataTable = styled(ReportDataTable)`
|
||||||
|
.table {
|
||||||
|
.tbody .tr {
|
||||||
|
.td {
|
||||||
|
border-bottom: 0;
|
||||||
|
padding-top: 0.32rem;
|
||||||
|
padding-bottom: 0.32rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|||||||
@@ -1,5 +1,16 @@
|
|||||||
|
import moment from 'moment';
|
||||||
import { transformToCamelCase, flatObject } from 'utils';
|
import { transformToCamelCase, flatObject } from 'utils';
|
||||||
|
|
||||||
export const transformFilterFormToQuery = (form) => {
|
export const transformFilterFormToQuery = (form) => {
|
||||||
return flatObject(transformToCamelCase(form));
|
return flatObject(transformToCamelCase(form));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getDefaultAPAgingSummaryQuery = () => {
|
||||||
|
return {
|
||||||
|
asDate: moment().endOf('day').format('YYYY-MM-DD'),
|
||||||
|
agingDaysBefore: 30,
|
||||||
|
agingPeriods: 3,
|
||||||
|
vendorsIds: [],
|
||||||
|
filterByOption: 'without-zero-balance',
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,38 +1,29 @@
|
|||||||
import React, { useState, useCallback, useEffect } from 'react';
|
import React, { useState, useCallback, useEffect } from 'react';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
|
||||||
import 'style/pages/FinancialStatements/ARAgingSummary.scss';
|
|
||||||
|
|
||||||
import { FinancialStatement } from 'components';
|
import { FinancialStatement } from 'components';
|
||||||
|
|
||||||
import ARAgingSummaryHeader from './ARAgingSummaryHeader';
|
import ARAgingSummaryHeader from './ARAgingSummaryHeader';
|
||||||
import ARAgingSummaryActionsBar from './ARAgingSummaryActionsBar';
|
import ARAgingSummaryActionsBar from './ARAgingSummaryActionsBar';
|
||||||
import ARAgingSummaryTable from './ARAgingSummaryTable';
|
|
||||||
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||||
import { ARAgingSummaryProvider } from './ARAgingSummaryProvider';
|
import { ARAgingSummaryProvider } from './ARAgingSummaryProvider';
|
||||||
import { ARAgingSummarySheetLoadingBar } from './components';
|
import { ARAgingSummarySheetLoadingBar } from './components';
|
||||||
|
import { ARAgingSummaryBody } from './ARAgingSummaryBody';
|
||||||
|
|
||||||
import withARAgingSummaryActions from './withARAgingSummaryActions'
|
import withARAgingSummaryActions from './withARAgingSummaryActions';
|
||||||
import withCurrentOrganization from '../../../containers/Organization/withCurrentOrganization';
|
|
||||||
|
|
||||||
|
import { getDefaultARAgingSummaryQuery } from './common';
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A/R aging summary report.
|
* A/R aging summary report.
|
||||||
*/
|
*/
|
||||||
function ReceivableAgingSummarySheet({
|
function ReceivableAgingSummarySheet({
|
||||||
// #withSettings
|
|
||||||
organizationName,
|
|
||||||
|
|
||||||
// #withARAgingSummaryActions
|
// #withARAgingSummaryActions
|
||||||
toggleARAgingSummaryFilterDrawer: toggleDisplayFilterDrawer
|
toggleARAgingSummaryFilterDrawer: toggleDisplayFilterDrawer,
|
||||||
}) {
|
}) {
|
||||||
const [filter, setFilter] = useState({
|
const [filter, setFilter] = useState({
|
||||||
asDate: moment().endOf('day').format('YYYY-MM-DD'),
|
...getDefaultARAgingSummaryQuery(),
|
||||||
agingDaysBefore: 30,
|
|
||||||
agingPeriods: 3,
|
|
||||||
customersIds: [],
|
|
||||||
filterByOption: 'without-zero-balance',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle filter submit.
|
// Handle filter submit.
|
||||||
@@ -48,11 +39,13 @@ function ReceivableAgingSummarySheet({
|
|||||||
const handleNumberFormatSubmit = (numberFormat) => {
|
const handleNumberFormatSubmit = (numberFormat) => {
|
||||||
setFilter({ ...filter, numberFormat });
|
setFilter({ ...filter, numberFormat });
|
||||||
};
|
};
|
||||||
|
|
||||||
// Hide the filter drawer once the page unmount.
|
// Hide the filter drawer once the page unmount.
|
||||||
useEffect(() => () => {
|
useEffect(
|
||||||
toggleDisplayFilterDrawer(false);
|
() => () => {
|
||||||
}, [toggleDisplayFilterDrawer]);
|
toggleDisplayFilterDrawer(false);
|
||||||
|
},
|
||||||
|
[toggleDisplayFilterDrawer],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ARAgingSummaryProvider filter={filter}>
|
<ARAgingSummaryProvider filter={filter}>
|
||||||
@@ -63,23 +56,16 @@ function ReceivableAgingSummarySheet({
|
|||||||
<ARAgingSummarySheetLoadingBar />
|
<ARAgingSummarySheetLoadingBar />
|
||||||
|
|
||||||
<DashboardPageContent>
|
<DashboardPageContent>
|
||||||
<FinancialStatement name={'AR-aging-summary'}>
|
<FinancialStatement>
|
||||||
<ARAgingSummaryHeader
|
<ARAgingSummaryHeader
|
||||||
pageFilter={filter}
|
pageFilter={filter}
|
||||||
onSubmitFilter={handleFilterSubmit}
|
onSubmitFilter={handleFilterSubmit}
|
||||||
/>
|
/>
|
||||||
<div class="financial-statement__body">
|
<ARAgingSummaryBody />
|
||||||
<ARAgingSummaryTable organizationName={organizationName} />
|
|
||||||
</div>
|
|
||||||
</FinancialStatement>
|
</FinancialStatement>
|
||||||
</DashboardPageContent>
|
</DashboardPageContent>
|
||||||
</ARAgingSummaryProvider>
|
</ARAgingSummaryProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default compose(
|
export default compose(withARAgingSummaryActions)(ReceivableAgingSummarySheet);
|
||||||
withCurrentOrganization(({ organization }) => ({
|
|
||||||
organizationName: organization.name,
|
|
||||||
})),
|
|
||||||
withARAgingSummaryActions
|
|
||||||
)(ReceivableAgingSummarySheet);
|
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import * as R from 'ramda';
|
||||||
|
|
||||||
|
import ARAgingSummaryTable from './ARAgingSummaryTable';
|
||||||
|
import { FinancialReportBody } from '../FinancialReportPage';
|
||||||
|
import { FinancialSheetSkeleton } from '../../../components';
|
||||||
|
|
||||||
|
import withCurrentOrganization from '../../../containers/Organization/withCurrentOrganization';
|
||||||
|
import { useARAgingSummaryContext } from './ARAgingSummaryProvider';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A/R Aging summary body.
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
*/
|
||||||
|
function ARAgingSummaryBodyJSX({
|
||||||
|
// #withCurrentOrganization
|
||||||
|
organizationName,
|
||||||
|
}) {
|
||||||
|
const { isARAgingLoading } = useARAgingSummaryContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FinancialReportBody>
|
||||||
|
{isARAgingLoading ? (
|
||||||
|
<FinancialSheetSkeleton />
|
||||||
|
) : (
|
||||||
|
<ARAgingSummaryTable organizationName={organizationName} />
|
||||||
|
)}
|
||||||
|
</FinancialReportBody>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ARAgingSummaryBody = R.compose(
|
||||||
|
withCurrentOrganization(({ organization }) => ({
|
||||||
|
organizationName: organization.name,
|
||||||
|
})),
|
||||||
|
)(ARAgingSummaryBodyJSX);
|
||||||
@@ -4,6 +4,7 @@ import { Formik, Form } from 'formik';
|
|||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { Tabs, Tab, Button, Intent } from '@blueprintjs/core';
|
import { Tabs, Tab, Button, Intent } from '@blueprintjs/core';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import FinancialStatementHeader from 'containers/FinancialStatements/FinancialStatementHeader';
|
import FinancialStatementHeader from 'containers/FinancialStatements/FinancialStatementHeader';
|
||||||
import ARAgingSummaryHeaderGeneral from './ARAgingSummaryHeaderGeneral';
|
import ARAgingSummaryHeaderGeneral from './ARAgingSummaryHeaderGeneral';
|
||||||
@@ -57,14 +58,12 @@ function ARAgingSummaryHeader({
|
|||||||
},
|
},
|
||||||
defaultValues,
|
defaultValues,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Handle form submit.
|
// Handle form submit.
|
||||||
const handleSubmit = (values, { setSubmitting }) => {
|
const handleSubmit = (values, { setSubmitting }) => {
|
||||||
onSubmitFilter(values);
|
onSubmitFilter(values);
|
||||||
toggleFilterDrawerDisplay(false);
|
toggleFilterDrawerDisplay(false);
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle cancel button click.
|
// Handle cancel button click.
|
||||||
const handleCancelClick = () => {
|
const handleCancelClick = () => {
|
||||||
toggleFilterDrawerDisplay(false);
|
toggleFilterDrawerDisplay(false);
|
||||||
@@ -75,7 +74,7 @@ function ARAgingSummaryHeader({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FinancialStatementHeader
|
<ARAgingDrawerHeader
|
||||||
isOpen={isFilterDrawerOpen}
|
isOpen={isFilterDrawerOpen}
|
||||||
drawerProps={{ onClose: handleDrawerClose }}
|
drawerProps={{ onClose: handleDrawerClose }}
|
||||||
>
|
>
|
||||||
@@ -103,7 +102,7 @@ function ARAgingSummaryHeader({
|
|||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
</Formik>
|
</Formik>
|
||||||
</FinancialStatementHeader>
|
</ARAgingDrawerHeader>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -113,3 +112,9 @@ export default compose(
|
|||||||
isFilterDrawerOpen: ARAgingSummaryFilterDrawer,
|
isFilterDrawerOpen: ARAgingSummaryFilterDrawer,
|
||||||
})),
|
})),
|
||||||
)(ARAgingSummaryHeader);
|
)(ARAgingSummaryHeader);
|
||||||
|
|
||||||
|
const ARAgingDrawerHeader = styled(FinancialStatementHeader)`
|
||||||
|
.bp3-drawer {
|
||||||
|
max-height: 520px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
import React, { useCallback } from 'react';
|
import React from 'react';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import DataTable from 'components/DataTable';
|
import styled from 'styled-components';
|
||||||
import FinancialSheet from 'components/FinancialSheet';
|
|
||||||
|
import { ReportDataTable, FinancialSheet } from 'components';
|
||||||
|
import { TableStyle } from 'common';
|
||||||
|
|
||||||
import { useARAgingSummaryContext } from './ARAgingSummaryProvider';
|
import { useARAgingSummaryContext } from './ARAgingSummaryProvider';
|
||||||
import { useARAgingSummaryColumns } from './components';
|
import { useARAgingSummaryColumns } from './components';
|
||||||
|
|
||||||
|
import { tableRowTypesToClassnames } from 'utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AR aging summary table sheet.
|
* AR aging summary table sheet.
|
||||||
*/
|
*/
|
||||||
@@ -19,24 +23,52 @@ export default function ReceivableAgingSummaryTable({
|
|||||||
// AR aging summary columns.
|
// AR aging summary columns.
|
||||||
const columns = useARAgingSummaryColumns();
|
const columns = useARAgingSummaryColumns();
|
||||||
|
|
||||||
const rowClassNames = (row) => [`row-type--${row.original.rowType}`];
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FinancialSheet
|
<FinancialSheet
|
||||||
companyName={organizationName}
|
companyName={organizationName}
|
||||||
name={'receivable-aging-summary'}
|
|
||||||
sheetType={intl.get('receivable_aging_summary')}
|
sheetType={intl.get('receivable_aging_summary')}
|
||||||
asDate={new Date()}
|
asDate={new Date()}
|
||||||
loading={isARAgingLoading}
|
loading={isARAgingLoading}
|
||||||
>
|
>
|
||||||
<DataTable
|
<ARAgingSummaryDataTable
|
||||||
className="bigcapital-datatable--financial-report"
|
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={ARAgingSummary.tableRows}
|
data={ARAgingSummary.tableRows}
|
||||||
rowClassNames={rowClassNames}
|
rowClassNames={tableRowTypesToClassnames}
|
||||||
noInitialFetch={true}
|
noInitialFetch={true}
|
||||||
sticky={true}
|
sticky={true}
|
||||||
|
styleName={TableStyle.Constrant}
|
||||||
/>
|
/>
|
||||||
</FinancialSheet>
|
</FinancialSheet>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const ARAgingSummaryDataTable = styled(ReportDataTable)`
|
||||||
|
.table {
|
||||||
|
.tbody .tr {
|
||||||
|
.td {
|
||||||
|
border-bottom: 0;
|
||||||
|
padding-top: 0.32rem;
|
||||||
|
padding-bottom: 0.32rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:not(.no-results) {
|
||||||
|
.td {
|
||||||
|
border-bottom: 0;
|
||||||
|
padding-top: 0.4rem;
|
||||||
|
padding-bottom: 0.4rem;
|
||||||
|
}
|
||||||
|
&:not(:first-child) .td {
|
||||||
|
border-top: 1px solid transparent;
|
||||||
|
}
|
||||||
|
&.row_type--total {
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
.td {
|
||||||
|
border-top: 1px solid #bbb;
|
||||||
|
border-bottom: 3px double #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|||||||
@@ -1,5 +1,19 @@
|
|||||||
|
import moment from 'moment';
|
||||||
import { transformToCamelCase, flatObject } from 'utils';
|
import { transformToCamelCase, flatObject } from 'utils';
|
||||||
|
|
||||||
export const transfromFilterFormToQuery = (form) => {
|
export const transfromFilterFormToQuery = (form) => {
|
||||||
return flatObject(transformToCamelCase(form));
|
return flatObject(transformToCamelCase(form));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the default A/R aging summary query.
|
||||||
|
*/
|
||||||
|
export const getDefaultARAgingSummaryQuery = () => {
|
||||||
|
return {
|
||||||
|
asDate: moment().endOf('day').format('YYYY-MM-DD'),
|
||||||
|
agingDaysBefore: 30,
|
||||||
|
agingPeriods: 3,
|
||||||
|
customersIds: [],
|
||||||
|
filterByOption: 'without-zero-balance',
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
|
|
||||||
import { useARAgingSummaryContext } from './ARAgingSummaryProvider';
|
import { useARAgingSummaryContext } from './ARAgingSummaryProvider';
|
||||||
|
import { If, FormattedMessage as T } from 'components';
|
||||||
|
|
||||||
import { getColumnWidth } from 'utils';
|
import { getColumnWidth } from 'utils';
|
||||||
import { FormattedMessage as T } from 'components';
|
import { Align } from 'common';
|
||||||
import { If } from 'components';
|
|
||||||
import FinancialLoadingBar from '../FinancialLoadingBar';
|
import FinancialLoadingBar from '../FinancialLoadingBar';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,6 +42,7 @@ export const useARAgingSummaryColumns = () => {
|
|||||||
width: getColumnWidth(tableRows, `current`, {
|
width: getColumnWidth(tableRows, `current`, {
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
}),
|
}),
|
||||||
|
align: Align.Right
|
||||||
},
|
},
|
||||||
...agingColumns.map((agingColumn, index) => ({
|
...agingColumns.map((agingColumn, index) => ({
|
||||||
Header: agingColumn,
|
Header: agingColumn,
|
||||||
@@ -47,6 +50,7 @@ export const useARAgingSummaryColumns = () => {
|
|||||||
width: getColumnWidth(tableRows, `aging-${index}`, {
|
width: getColumnWidth(tableRows, `aging-${index}`, {
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
}),
|
}),
|
||||||
|
align: Align.Right
|
||||||
})),
|
})),
|
||||||
{
|
{
|
||||||
Header: <T id={'total'} />,
|
Header: <T id={'total'} />,
|
||||||
@@ -56,6 +60,7 @@ export const useARAgingSummaryColumns = () => {
|
|||||||
width: getColumnWidth(tableRows, 'total', {
|
width: getColumnWidth(tableRows, 'total', {
|
||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
}),
|
}),
|
||||||
|
align: Align.Right
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[tableRows, agingColumns],
|
[tableRows, agingColumns],
|
||||||
|
|||||||
@@ -1,57 +1,47 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import 'style/pages/FinancialStatements/BalanceSheet.scss';
|
|
||||||
|
|
||||||
import { BalanceSheetAlerts, BalanceSheetLoadingBar } from './components';
|
import { BalanceSheetAlerts, BalanceSheetLoadingBar } from './components';
|
||||||
import { FinancialStatement } from 'components';
|
import { FinancialStatement } from 'components';
|
||||||
|
|
||||||
import BalanceSheetHeader from './BalanceSheetHeader';
|
import BalanceSheetHeader from './BalanceSheetHeader';
|
||||||
import BalanceSheetTable from './BalanceSheetTable';
|
|
||||||
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||||
import BalanceSheetActionsBar from './BalanceSheetActionsBar';
|
import BalanceSheetActionsBar from './BalanceSheetActionsBar';
|
||||||
import { BalanceSheetProvider } from './BalanceSheetProvider';
|
import { BalanceSheetProvider } from './BalanceSheetProvider';
|
||||||
|
import { BalanceSheetBody } from './BalanceSheetBody';
|
||||||
|
|
||||||
import withBalanceSheetActions from './withBalanceSheetActions';
|
import withBalanceSheetActions from './withBalanceSheetActions';
|
||||||
import withCurrentOrganization from '../../../containers/Organization/withCurrentOrganization';
|
|
||||||
|
|
||||||
|
import { useBalanceSheetQuery } from './utils';
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Balance sheet.
|
* Balance sheet.
|
||||||
|
* @returns {React.JSX}
|
||||||
*/
|
*/
|
||||||
function BalanceSheet({
|
function BalanceSheet({
|
||||||
// #withCurrentOrganization
|
|
||||||
organizationName,
|
|
||||||
|
|
||||||
// #withBalanceSheetActions
|
// #withBalanceSheetActions
|
||||||
toggleBalanceSheetFilterDrawer,
|
toggleBalanceSheetFilterDrawer,
|
||||||
}) {
|
}) {
|
||||||
const [filter, setFilter] = useState({
|
// Balance sheet query.
|
||||||
fromDate: moment().startOf('year').format('YYYY-MM-DD'),
|
const { query, setLocationQuery } = useBalanceSheetQuery();
|
||||||
toDate: moment().endOf('year').format('YYYY-MM-DD'),
|
|
||||||
basis: 'cash',
|
|
||||||
displayColumnsType: 'total',
|
|
||||||
filterByOption: 'without-zero-balance',
|
|
||||||
});
|
|
||||||
|
|
||||||
// Handle re-fetch balance sheet after filter change.
|
// Handle re-fetch balance sheet after filter change.
|
||||||
const handleFilterSubmit = (filter) => {
|
const handleFilterSubmit = (filter) => {
|
||||||
const _filter = {
|
const newFilter = {
|
||||||
...filter,
|
...filter,
|
||||||
fromDate: moment(filter.fromDate).format('YYYY-MM-DD'),
|
fromDate: moment(filter.fromDate).format('YYYY-MM-DD'),
|
||||||
toDate: moment(filter.toDate).format('YYYY-MM-DD'),
|
toDate: moment(filter.toDate).format('YYYY-MM-DD'),
|
||||||
};
|
};
|
||||||
setFilter({ ..._filter });
|
setLocationQuery({ ...newFilter });
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle number format submit.
|
// Handle number format submit.
|
||||||
const handleNumberFormatSubmit = (values) => {
|
const handleNumberFormatSubmit = (values) => {
|
||||||
setFilter({
|
setLocationQuery({
|
||||||
...filter,
|
...query,
|
||||||
numberFormat: values,
|
numberFormat: values,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
// Hides the balance sheet filter drawer once the page unmount.
|
// Hides the balance sheet filter drawer once the page unmount.
|
||||||
useEffect(
|
useEffect(
|
||||||
() => () => {
|
() => () => {
|
||||||
@@ -61,33 +51,25 @@ function BalanceSheet({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BalanceSheetProvider filter={filter}>
|
<BalanceSheetProvider filter={query}>
|
||||||
<BalanceSheetActionsBar
|
<BalanceSheetActionsBar
|
||||||
numberFormat={filter.numberFormat}
|
numberFormat={query.numberFormat}
|
||||||
onNumberFormatSubmit={handleNumberFormatSubmit}
|
onNumberFormatSubmit={handleNumberFormatSubmit}
|
||||||
/>
|
/>
|
||||||
<BalanceSheetLoadingBar />
|
<BalanceSheetLoadingBar />
|
||||||
|
<BalanceSheetAlerts />
|
||||||
|
|
||||||
<DashboardPageContent>
|
<DashboardPageContent>
|
||||||
<FinancialStatement>
|
<FinancialStatement>
|
||||||
<BalanceSheetHeader
|
<BalanceSheetHeader
|
||||||
pageFilter={filter}
|
pageFilter={query}
|
||||||
onSubmitFilter={handleFilterSubmit}
|
onSubmitFilter={handleFilterSubmit}
|
||||||
/>
|
/>
|
||||||
<div class="financial-statement__body">
|
<BalanceSheetBody />
|
||||||
<BalanceSheetTable companyName={organizationName} />
|
|
||||||
</div>
|
|
||||||
</FinancialStatement>
|
</FinancialStatement>
|
||||||
</DashboardPageContent>
|
</DashboardPageContent>
|
||||||
|
|
||||||
<BalanceSheetAlerts />
|
|
||||||
</BalanceSheetProvider>
|
</BalanceSheetProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default compose(
|
export default compose(withBalanceSheetActions)(BalanceSheet);
|
||||||
withCurrentOrganization(({ organization }) => ({
|
|
||||||
organizationName: organization.name,
|
|
||||||
})),
|
|
||||||
withBalanceSheetActions,
|
|
||||||
)(BalanceSheet);
|
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import BalanceSheetTable from './BalanceSheetTable';
|
||||||
|
import { FinancialReportBody } from '../FinancialReportPage';
|
||||||
|
|
||||||
|
import withCurrentOrganization from 'containers/Organization/withCurrentOrganization';
|
||||||
|
import { useBalanceSheetContext } from './BalanceSheetProvider';
|
||||||
|
import { FinancialSheetSkeleton } from '../../../components/FinancialSheet';
|
||||||
|
import { compose } from 'utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Balance sheet body JSX.
|
||||||
|
* @returns {React.JSX}
|
||||||
|
*/
|
||||||
|
function BalanceSheetBodyJSX({
|
||||||
|
// #withCurrentOrganization
|
||||||
|
organizationName,
|
||||||
|
}) {
|
||||||
|
const { isLoading } = useBalanceSheetContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FinancialReportBody>
|
||||||
|
{isLoading ? (
|
||||||
|
<FinancialSheetSkeleton />
|
||||||
|
) : (
|
||||||
|
<BalanceSheetTable companyName={organizationName} />
|
||||||
|
)}
|
||||||
|
</FinancialReportBody>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const BalanceSheetBody = compose(
|
||||||
|
withCurrentOrganization(({ organization }) => ({
|
||||||
|
organizationName: organization.name,
|
||||||
|
})),
|
||||||
|
)(BalanceSheetBodyJSX);
|
||||||
@@ -1,19 +1,22 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Tabs, Tab, Button, Intent } from '@blueprintjs/core';
|
import { Tabs, Tab, Button, Intent } from '@blueprintjs/core';
|
||||||
import { FormattedMessage as T } from 'components';
|
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { Formik, Form } from 'formik';
|
import { Formik, Form } from 'formik';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
import { FormattedMessage as T } from 'components';
|
||||||
|
|
||||||
import withBalanceSheet from './withBalanceSheet';
|
import withBalanceSheet from './withBalanceSheet';
|
||||||
import withBalanceSheetActions from './withBalanceSheetActions';
|
import withBalanceSheetActions from './withBalanceSheetActions';
|
||||||
|
|
||||||
import BalanceSheetHeaderGeneralPanal from './BalanceSheetHeaderGeneralPanal';
|
import BalanceSheetHeaderGeneralPanal from './BalanceSheetHeaderGeneralPanal';
|
||||||
|
import BalanceSheetHeaderComparisonPanal from './BalanceSheetHeaderComparisonPanal';
|
||||||
import FinancialStatementHeader from '../../FinancialStatements/FinancialStatementHeader';
|
import FinancialStatementHeader from '../../FinancialStatements/FinancialStatementHeader';
|
||||||
|
|
||||||
import { compose, transformToForm } from 'utils';
|
import { compose, transformToForm } from 'utils';
|
||||||
import {
|
import {
|
||||||
getBalanceSheetHeaderDefaultValues,
|
|
||||||
getBalanceSheetHeaderValidationSchema,
|
getBalanceSheetHeaderValidationSchema,
|
||||||
|
getDefaultBalanceSheetQuery,
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -30,7 +33,7 @@ function BalanceSheetHeader({
|
|||||||
// #withBalanceSheetActions
|
// #withBalanceSheetActions
|
||||||
toggleBalanceSheetFilterDrawer: toggleFilterDrawer,
|
toggleBalanceSheetFilterDrawer: toggleFilterDrawer,
|
||||||
}) {
|
}) {
|
||||||
const defaultValues = getBalanceSheetHeaderDefaultValues();
|
const defaultValues = getDefaultBalanceSheetQuery();
|
||||||
|
|
||||||
// Filter form initial values.
|
// Filter form initial values.
|
||||||
const initialValues = transformToForm(
|
const initialValues = transformToForm(
|
||||||
@@ -42,7 +45,6 @@ function BalanceSheetHeader({
|
|||||||
},
|
},
|
||||||
defaultValues,
|
defaultValues,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Validation schema.
|
// Validation schema.
|
||||||
const validationSchema = getBalanceSheetHeaderValidationSchema();
|
const validationSchema = getBalanceSheetHeaderValidationSchema();
|
||||||
|
|
||||||
@@ -64,9 +66,11 @@ function BalanceSheetHeader({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FinancialStatementHeader
|
<BalanceSheetFinancialHeader
|
||||||
isOpen={balanceSheetDrawerFilter}
|
isOpen={balanceSheetDrawerFilter}
|
||||||
drawerProps={{ onClose: handleDrawerClose }}
|
drawerProps={{
|
||||||
|
onClose: handleDrawerClose,
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<Formik
|
<Formik
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
@@ -80,6 +84,11 @@ function BalanceSheetHeader({
|
|||||||
title={<T id={'general'} />}
|
title={<T id={'general'} />}
|
||||||
panel={<BalanceSheetHeaderGeneralPanal />}
|
panel={<BalanceSheetHeaderGeneralPanal />}
|
||||||
/>
|
/>
|
||||||
|
<Tab
|
||||||
|
id="comparison"
|
||||||
|
title={<T id={'balance_sheet.comparisons'} />}
|
||||||
|
panel={<BalanceSheetHeaderComparisonPanal />}
|
||||||
|
/>
|
||||||
</Tabs>
|
</Tabs>
|
||||||
|
|
||||||
<div class="financial-header-drawer__footer">
|
<div class="financial-header-drawer__footer">
|
||||||
@@ -92,7 +101,7 @@ function BalanceSheetHeader({
|
|||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
</Formik>
|
</Formik>
|
||||||
</FinancialStatementHeader>
|
</BalanceSheetFinancialHeader>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,3 +111,9 @@ export default compose(
|
|||||||
})),
|
})),
|
||||||
withBalanceSheetActions,
|
withBalanceSheetActions,
|
||||||
)(BalanceSheetHeader);
|
)(BalanceSheetHeader);
|
||||||
|
|
||||||
|
const BalanceSheetFinancialHeader = styled(FinancialStatementHeader)`
|
||||||
|
.bp3-drawer {
|
||||||
|
max-height: 520px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|||||||
@@ -0,0 +1,155 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { FastField, Field } from 'formik';
|
||||||
|
import { FormGroup, Checkbox } from '@blueprintjs/core';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
import { Row, Col, FieldHint, FormattedMessage as T } from 'components';
|
||||||
|
import {
|
||||||
|
handlePreviousYearCheckBoxChange,
|
||||||
|
handlePreviousYearChangeCheckboxChange,
|
||||||
|
handlePreviousPeriodCheckBoxChange,
|
||||||
|
handlePreivousPeriodPercentageCheckboxChange,
|
||||||
|
handlePreviousYearPercentageCheckboxChange,
|
||||||
|
handlePreviousPeriodChangeCheckboxChange,
|
||||||
|
} from './utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Balance sheet header - Comparison panal.
|
||||||
|
*/
|
||||||
|
export default function BalanceSheetHeaderComparisonPanal() {
|
||||||
|
return (
|
||||||
|
<BalanceSheetComparisonWrap>
|
||||||
|
{/**----------- Previous Year -----------*/}
|
||||||
|
<Field name={'previousYear'} type={'checkbox'}>
|
||||||
|
{({ form, field }) => (
|
||||||
|
<FormGroup labelInfo={<FieldHint />}>
|
||||||
|
<Checkbox
|
||||||
|
inline={true}
|
||||||
|
label={<T id={'balance_sheet.previous_year'} />}
|
||||||
|
{...field}
|
||||||
|
onChange={handlePreviousYearCheckBoxChange(form)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
<Row>
|
||||||
|
<Col xs={3}>
|
||||||
|
<Field name={'previousYearAmountChange'} type={'checkbox'}>
|
||||||
|
{({ form, field }) => (
|
||||||
|
<FormGroup labelInfo={<FieldHint />}>
|
||||||
|
<Checkbox
|
||||||
|
inline={true}
|
||||||
|
small={true}
|
||||||
|
label={<T id={'balance_sheet.total_change'} />}
|
||||||
|
{...field}
|
||||||
|
onChange={handlePreviousYearChangeCheckboxChange(form)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
</Field>
|
||||||
|
</Col>
|
||||||
|
<Col xs={3}>
|
||||||
|
<FastField name={'previousYearPercentageChange'} type={'checkbox'}>
|
||||||
|
{({ form, field }) => (
|
||||||
|
<FormGroup labelInfo={<FieldHint />}>
|
||||||
|
<Checkbox
|
||||||
|
inline={true}
|
||||||
|
label={<T id={'balance_sheet.change'} />}
|
||||||
|
{...field}
|
||||||
|
onChange={handlePreviousYearPercentageCheckboxChange(form)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
</FastField>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
{/*------------ Previous Period -----------*/}
|
||||||
|
<FastField name={'previousPeriod'} type={'checkbox'}>
|
||||||
|
{({ form, field }) => (
|
||||||
|
<FormGroup labelInfo={<FieldHint />}>
|
||||||
|
<Checkbox
|
||||||
|
inline={true}
|
||||||
|
small={true}
|
||||||
|
label={<T id={'balance_sheet.previous_period'} />}
|
||||||
|
{...field}
|
||||||
|
onChange={handlePreviousPeriodCheckBoxChange(form)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
</FastField>
|
||||||
|
<Row>
|
||||||
|
<Col xs={3}>
|
||||||
|
<FastField name={'previousPeriodAmountChange'} type={'checkbox'}>
|
||||||
|
{({ form, field }) => (
|
||||||
|
<FormGroup labelInfo={<FieldHint />}>
|
||||||
|
<Checkbox
|
||||||
|
inline={true}
|
||||||
|
small={true}
|
||||||
|
label={<T id={'balance_sheet.total_change'} />}
|
||||||
|
{...field}
|
||||||
|
onChange={handlePreviousPeriodChangeCheckboxChange(form)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
</FastField>
|
||||||
|
</Col>
|
||||||
|
<Col xs={3}>
|
||||||
|
<FastField name={'previousPeriodPercentageChange'} type={'checkbox'}>
|
||||||
|
{({ form, field }) => (
|
||||||
|
<FormGroup labelInfo={<FieldHint />}>
|
||||||
|
<Checkbox
|
||||||
|
inline={true}
|
||||||
|
label={<T id={'balance_sheet.change'} />}
|
||||||
|
{...field}
|
||||||
|
onChange={handlePreivousPeriodPercentageCheckboxChange(form)}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
</FastField>
|
||||||
|
</Col>
|
||||||
|
</Row>
|
||||||
|
|
||||||
|
{/**----------- % of Column -----------*/}
|
||||||
|
<FastField name={'percentageOfColumn'} type={'checkbox'}>
|
||||||
|
{({ field }) => (
|
||||||
|
<FormGroup labelInfo={<FieldHint />}>
|
||||||
|
<Checkbox
|
||||||
|
inline={true}
|
||||||
|
small={true}
|
||||||
|
label={<T id={'balance_sheet.percentage_of_column'} />}
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
</FastField>
|
||||||
|
|
||||||
|
{/**----------- % of Row -----------*/}
|
||||||
|
<FastField name={'percentageOfRow'} type={'checkbox'}>
|
||||||
|
{({ field }) => (
|
||||||
|
<FormGroup labelInfo={<FieldHint />}>
|
||||||
|
<Checkbox
|
||||||
|
inline={true}
|
||||||
|
small={true}
|
||||||
|
label={<T id={'balance_sheet.percentage_of_row'} />}
|
||||||
|
{...field}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
)}
|
||||||
|
</FastField>
|
||||||
|
</BalanceSheetComparisonWrap>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
const BalanceSheetComparisonWrap = styled.div`
|
||||||
|
.row {
|
||||||
|
margin-left: 0.15rem;
|
||||||
|
.col {
|
||||||
|
min-width: 150px !important;
|
||||||
|
max-width: 190px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.bp3-form-group {
|
||||||
|
margin-bottom: 3px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { createContext, useContext } from 'react';
|
import React, { createContext, useContext } from 'react';
|
||||||
|
|
||||||
import FinancialReportPage from '../FinancialReportPage';
|
import FinancialReportPage from '../FinancialReportPage';
|
||||||
import { useBalanceSheet } from 'hooks/query';
|
import { useBalanceSheet } from 'hooks/query';
|
||||||
import { transformFilterFormToQuery } from '../common';
|
import { transformFilterFormToQuery } from '../common';
|
||||||
@@ -10,7 +11,6 @@ function BalanceSheetProvider({ filter, ...props }) {
|
|||||||
const query = React.useMemo(() => transformFilterFormToQuery(filter), [
|
const query = React.useMemo(() => transformFilterFormToQuery(filter), [
|
||||||
filter,
|
filter,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Fetches the balance sheet report.
|
// Fetches the balance sheet report.
|
||||||
const {
|
const {
|
||||||
data: balanceSheet,
|
data: balanceSheet,
|
||||||
|
|||||||
@@ -1,13 +1,15 @@
|
|||||||
import React, { useMemo, useCallback } from 'react';
|
import React from 'react';
|
||||||
|
import styled from 'styled-components';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import classNames from 'classnames';
|
|
||||||
|
|
||||||
import FinancialSheet from 'components/FinancialSheet';
|
import { ReportDataTable, FinancialSheet } from 'components';
|
||||||
import DataTable from 'components/DataTable';
|
|
||||||
import { CellTextSpan } from 'components/Datatable/Cells';
|
|
||||||
import { useBalanceSheetContext } from './BalanceSheetProvider';
|
import { useBalanceSheetContext } from './BalanceSheetProvider';
|
||||||
|
|
||||||
import { defaultExpanderReducer, getColumnWidth } from 'utils';
|
import { defaultExpanderReducer, tableRowTypesToClassnames } from 'utils';
|
||||||
|
import { useBalanceSheetColumns } from './components';
|
||||||
|
|
||||||
|
import { TableStyle } from 'common';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Balance sheet table.
|
* Balance sheet table.
|
||||||
@@ -16,91 +18,73 @@ export default function BalanceSheetTable({
|
|||||||
// #ownProps
|
// #ownProps
|
||||||
companyName,
|
companyName,
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
|
|
||||||
// Balance sheet context.
|
// Balance sheet context.
|
||||||
const {
|
const {
|
||||||
balanceSheet: { tableRows, columns, query },
|
balanceSheet: { table, query },
|
||||||
isLoading,
|
|
||||||
} = useBalanceSheetContext();
|
} = useBalanceSheetContext();
|
||||||
|
|
||||||
const tableColumns = useMemo(
|
// Retrieve the database columns.
|
||||||
() => [
|
const tableColumns = useBalanceSheetColumns();
|
||||||
{
|
|
||||||
Header: intl.get('account_name'),
|
// Retrieve default expanded rows of balance sheet.
|
||||||
accessor: (row) => (row.code ? `${row.name} - ${row.code}` : row.name),
|
const expandedRows = React.useMemo(
|
||||||
className: 'account_name',
|
() => defaultExpanderReducer(table.rows, 3),
|
||||||
textOverview: true,
|
[table],
|
||||||
width: 240,
|
|
||||||
},
|
|
||||||
...(query.display_columns_type === 'total'
|
|
||||||
? [
|
|
||||||
{
|
|
||||||
Header: intl.get('total'),
|
|
||||||
accessor: 'total.formatted_amount',
|
|
||||||
Cell: CellTextSpan,
|
|
||||||
className: 'total',
|
|
||||||
width: 140,
|
|
||||||
},
|
|
||||||
]
|
|
||||||
: []),
|
|
||||||
...(query.display_columns_type === 'date_periods'
|
|
||||||
? columns.map((column, index) => ({
|
|
||||||
id: `date_period_${index}`,
|
|
||||||
Header: column,
|
|
||||||
Cell: CellTextSpan,
|
|
||||||
accessor: `total_periods[${index}].formatted_amount`,
|
|
||||||
className: classNames('total-period', `total-periods-${index}`),
|
|
||||||
width: getColumnWidth(
|
|
||||||
tableRows,
|
|
||||||
`total_periods.${index}.formatted_amount`,
|
|
||||||
{ minWidth: 100 },
|
|
||||||
),
|
|
||||||
}))
|
|
||||||
: []),
|
|
||||||
],
|
|
||||||
[query, columns, tableRows],
|
|
||||||
);
|
);
|
||||||
|
|
||||||
// Calculates the default expanded rows of balance sheet table.
|
|
||||||
const expandedRows = useMemo(() => defaultExpanderReducer(tableRows, 4), [tableRows]);
|
|
||||||
|
|
||||||
const rowClassNames = useCallback((row) => {
|
|
||||||
const { original } = row;
|
|
||||||
const rowTypes = Array.isArray(original.row_types)
|
|
||||||
? original.row_types
|
|
||||||
: [original.row_types];
|
|
||||||
|
|
||||||
return {
|
|
||||||
...rowTypes.reduce((acc, rowType) => {
|
|
||||||
acc[`row_type--${rowType}`] = rowType;
|
|
||||||
return acc;
|
|
||||||
}, {}),
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FinancialSheet
|
<FinancialSheet
|
||||||
name="balance-sheet"
|
|
||||||
companyName={companyName}
|
companyName={companyName}
|
||||||
sheetType={intl.get('balance_sheet')}
|
sheetType={intl.get('balance_sheet')}
|
||||||
fromDate={query.from_date}
|
asDate={query.to_date}
|
||||||
toDate={query.to_date}
|
|
||||||
basis={query.basis}
|
basis={query.basis}
|
||||||
loading={isLoading}
|
|
||||||
>
|
>
|
||||||
<DataTable
|
<BalanceSheetDataTable
|
||||||
className="bigcapital-datatable--financial-report"
|
|
||||||
columns={tableColumns}
|
columns={tableColumns}
|
||||||
data={tableRows}
|
data={table.rows}
|
||||||
rowClassNames={rowClassNames}
|
rowClassNames={tableRowTypesToClassnames}
|
||||||
noInitialFetch={true}
|
noInitialFetch={true}
|
||||||
expandable={true}
|
expandable={true}
|
||||||
expanded={expandedRows}
|
expanded={expandedRows}
|
||||||
expandToggleColumn={1}
|
expandToggleColumn={1}
|
||||||
expandColumnSpace={0.8}
|
expandColumnSpace={0.8}
|
||||||
// sticky={true}
|
headerLoading={true}
|
||||||
|
sticky={true}
|
||||||
|
styleName={TableStyle.Constrant}
|
||||||
/>
|
/>
|
||||||
</FinancialSheet>
|
</FinancialSheet>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const BalanceSheetDataTable = styled(ReportDataTable)`
|
||||||
|
.table {
|
||||||
|
.tbody .tr {
|
||||||
|
.td {
|
||||||
|
border-bottom: 0;
|
||||||
|
padding-top: 0.32rem;
|
||||||
|
padding-bottom: 0.32rem;
|
||||||
|
}
|
||||||
|
&.is-expanded {
|
||||||
|
.td:not(.name) .cell-inner {
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.row_type--TOTAL {
|
||||||
|
.td {
|
||||||
|
font-weight: 500;
|
||||||
|
border-top: 1px solid #bbb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:last-of-type .td {
|
||||||
|
border-bottom: 1px solid #bbb;
|
||||||
|
}
|
||||||
|
&.row_type--TOTAL.row-id--ASSETS,
|
||||||
|
&.row_type--TOTAL.row-id--LIABILITY_EQUITY {
|
||||||
|
.td {
|
||||||
|
border-bottom: 3px double #000;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Button } from '@blueprintjs/core';
|
import { Button } from '@blueprintjs/core';
|
||||||
import { Icon, If } from 'components';
|
|
||||||
|
import { FormattedMessage as T, Icon, If } from 'components';
|
||||||
|
|
||||||
import { useBalanceSheetContext } from './BalanceSheetProvider';
|
import { useBalanceSheetContext } from './BalanceSheetProvider';
|
||||||
import { FormattedMessage as T } from 'components';
|
|
||||||
import FinancialLoadingBar from '../FinancialLoadingBar';
|
import FinancialLoadingBar from '../FinancialLoadingBar';
|
||||||
|
import { FinancialComputeAlert } from '../FinancialReportPage';
|
||||||
|
import { dynamicColumns } from './dynamicColumns';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Balance sheet alerts.
|
* Balance sheet alerts.
|
||||||
@@ -17,19 +20,18 @@ export function BalanceSheetAlerts() {
|
|||||||
refetchBalanceSheet();
|
refetchBalanceSheet();
|
||||||
};
|
};
|
||||||
// Can't display any error if the report is loading.
|
// Can't display any error if the report is loading.
|
||||||
if (isLoading) {
|
if (isLoading) return null;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<If condition={balanceSheet.meta.is_cost_compute_running}>
|
<If condition={balanceSheet.meta.is_cost_compute_running}>
|
||||||
<div class="alert-compute-running">
|
<FinancialComputeAlert>
|
||||||
<Icon icon="info-block" iconSize={12} />{' '}
|
<Icon icon="info-block" iconSize={12} />{' '}
|
||||||
<T id={'just_a_moment_we_re_calculating_your_cost_transactions'} />
|
<T id={'just_a_moment_we_re_calculating_your_cost_transactions'} />
|
||||||
|
|
||||||
<Button onClick={handleRecalcReport} minimal={true} small={true}>
|
<Button onClick={handleRecalcReport} minimal={true} small={true}>
|
||||||
<T id={'report.compute_running.refresh'} />
|
<T id={'report.compute_running.refresh'} />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</FinancialComputeAlert>
|
||||||
</If>
|
</If>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -46,3 +48,18 @@ export function BalanceSheetLoadingBar() {
|
|||||||
</If>
|
</If>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve balance sheet columns.
|
||||||
|
*/
|
||||||
|
export const useBalanceSheetColumns = () => {
|
||||||
|
// Balance sheet context.
|
||||||
|
const {
|
||||||
|
balanceSheet: { table },
|
||||||
|
} = useBalanceSheetContext();
|
||||||
|
|
||||||
|
return React.useMemo(
|
||||||
|
() => dynamicColumns(table.columns, table.rows),
|
||||||
|
[table],
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|||||||
@@ -0,0 +1,333 @@
|
|||||||
|
import * as R from 'ramda';
|
||||||
|
import { isEmpty } from 'lodash';
|
||||||
|
|
||||||
|
import { Align } from 'common';
|
||||||
|
import { CellTextSpan } from 'components/Datatable/Cells';
|
||||||
|
import { getColumnWidth } from 'utils';
|
||||||
|
|
||||||
|
const getTableCellValueAccessor = (index) => `cells[${index}].value`;
|
||||||
|
|
||||||
|
const getReportColWidth = (data, accessor, headerText) => {
|
||||||
|
return getColumnWidth(
|
||||||
|
data,
|
||||||
|
accessor,
|
||||||
|
{ magicSpacing: 10, minWidth: 100 },
|
||||||
|
headerText,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Account name column mapper.
|
||||||
|
*/
|
||||||
|
const accountNameMapper = R.curry((data, column) => {
|
||||||
|
const accessor = getTableCellValueAccessor(column.cell_index);
|
||||||
|
const width = getReportColWidth(data, accessor, column.label);
|
||||||
|
|
||||||
|
return {
|
||||||
|
key: column.key,
|
||||||
|
Header: column.label,
|
||||||
|
accessor,
|
||||||
|
className: column.key,
|
||||||
|
textOverview: true,
|
||||||
|
width: Math.max(width, 300),
|
||||||
|
sticky: Align.Left,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assoc columns to total column.
|
||||||
|
*/
|
||||||
|
const assocColumnsToTotalColumn = R.curry((data, column, columnAccessor) => {
|
||||||
|
const columns = totalColumnsComposer(data, column);
|
||||||
|
|
||||||
|
return R.assoc('columns', columns, columnAccessor);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detarmines whether the given column has children columns.
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
const isColumnHasColumns = (column) => !isEmpty(column.children);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} data
|
||||||
|
* @param {*} column
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const dateRangeSoloColumnAttrs = (data, column) => {
|
||||||
|
const accessor = getTableCellValueAccessor(column.cell_index);
|
||||||
|
|
||||||
|
return {
|
||||||
|
accessor,
|
||||||
|
width: getReportColWidth(data, accessor),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date range columns mapper.
|
||||||
|
*/
|
||||||
|
const dateRangeMapper = R.curry((data, column) => {
|
||||||
|
const isDateColumnHasColumns = isColumnHasColumns(column);
|
||||||
|
|
||||||
|
const columnAccessor = {
|
||||||
|
Header: column.label,
|
||||||
|
key: column.key,
|
||||||
|
disableSortBy: true,
|
||||||
|
textOverview: true,
|
||||||
|
align: isDateColumnHasColumns ? Align.Center : Align.Right,
|
||||||
|
};
|
||||||
|
return R.compose(
|
||||||
|
R.when(
|
||||||
|
R.always(isDateColumnHasColumns),
|
||||||
|
assocColumnsToTotalColumn(data, column),
|
||||||
|
),
|
||||||
|
R.when(
|
||||||
|
R.always(!isDateColumnHasColumns),
|
||||||
|
R.mergeLeft(dateRangeSoloColumnAttrs(data, column)),
|
||||||
|
),
|
||||||
|
)(columnAccessor);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total column mapper.
|
||||||
|
*/
|
||||||
|
const totalMapper = R.curry((data, column) => {
|
||||||
|
const hasChildren = !isEmpty(column.children);
|
||||||
|
const accessor = getTableCellValueAccessor(column.cell_index);
|
||||||
|
const width = getReportColWidth(data, accessor, column.label);
|
||||||
|
|
||||||
|
const columnAccessor = {
|
||||||
|
key: column.key,
|
||||||
|
Header: column.label,
|
||||||
|
accessor,
|
||||||
|
textOverview: true,
|
||||||
|
Cell: CellTextSpan,
|
||||||
|
width,
|
||||||
|
disableSortBy: true,
|
||||||
|
align: hasChildren ? Align.Center : Align.Right,
|
||||||
|
};
|
||||||
|
return R.compose(
|
||||||
|
R.when(R.always(hasChildren), assocColumnsToTotalColumn(data, column)),
|
||||||
|
)(columnAccessor);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `Percentage of column` column accessor.
|
||||||
|
*/
|
||||||
|
const percentageOfColumnAccessor = R.curry((data, column) => {
|
||||||
|
const accessor = getTableCellValueAccessor(column.cell_index);
|
||||||
|
const width = getReportColWidth(data, accessor, column.label);
|
||||||
|
|
||||||
|
return {
|
||||||
|
Header: column.label,
|
||||||
|
key: column.key,
|
||||||
|
accessor,
|
||||||
|
width,
|
||||||
|
align: Align.Right,
|
||||||
|
disableSortBy: true,
|
||||||
|
textOverview: true,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `Percentage of row` column accessor.
|
||||||
|
*/
|
||||||
|
const percentageOfRowAccessor = R.curry((data, column) => {
|
||||||
|
const accessor = getTableCellValueAccessor(column.cell_index);
|
||||||
|
const width = getReportColWidth(data, accessor, column.label);
|
||||||
|
|
||||||
|
return {
|
||||||
|
Header: column.label,
|
||||||
|
key: column.key,
|
||||||
|
accessor,
|
||||||
|
width,
|
||||||
|
align: Align.Right,
|
||||||
|
disableSortBy: true,
|
||||||
|
textOverview: true,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Previous year column accessor.
|
||||||
|
*/
|
||||||
|
const previousYearAccessor = R.curry((data, column) => {
|
||||||
|
const accessor = getTableCellValueAccessor(column.cell_index);
|
||||||
|
const width = getReportColWidth(data, accessor, column.label);
|
||||||
|
|
||||||
|
return {
|
||||||
|
Header: column.label,
|
||||||
|
key: column.key,
|
||||||
|
accessor,
|
||||||
|
width,
|
||||||
|
align: Align.Right,
|
||||||
|
disableSortBy: true,
|
||||||
|
textOverview: true,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pervious year change column accessor.
|
||||||
|
*/
|
||||||
|
const previousYearChangeAccessor = R.curry((data, column) => {
|
||||||
|
const accessor = getTableCellValueAccessor(column.cell_index);
|
||||||
|
const width = getReportColWidth(data, accessor, column.label);
|
||||||
|
|
||||||
|
return {
|
||||||
|
Header: column.label,
|
||||||
|
key: column.key,
|
||||||
|
accessor,
|
||||||
|
width,
|
||||||
|
align: Align.Right,
|
||||||
|
disableSortBy: true,
|
||||||
|
textOverview: true,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Previous year percentage column accessor.
|
||||||
|
*/
|
||||||
|
const previousYearPercentageAccessor = R.curry((data, column) => {
|
||||||
|
const accessor = getTableCellValueAccessor(column.cell_index);
|
||||||
|
const width = getReportColWidth(data, accessor, column.label);
|
||||||
|
|
||||||
|
return {
|
||||||
|
Header: column.label,
|
||||||
|
key: column.key,
|
||||||
|
accessor,
|
||||||
|
width,
|
||||||
|
align: Align.Right,
|
||||||
|
disableSortBy: true,
|
||||||
|
textOverview: true,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Previous period column accessor.
|
||||||
|
*/
|
||||||
|
const previousPeriodAccessor = R.curry((data, column) => {
|
||||||
|
const accessor = getTableCellValueAccessor(column.cell_index);
|
||||||
|
const width = getReportColWidth(data, accessor, column.label);
|
||||||
|
|
||||||
|
return {
|
||||||
|
Header: column.label,
|
||||||
|
key: column.key,
|
||||||
|
accessor,
|
||||||
|
width,
|
||||||
|
align: Align.Right,
|
||||||
|
disableSortBy: true,
|
||||||
|
textOverview: true,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Previous period change column accessor.
|
||||||
|
*/
|
||||||
|
const previousPeriodChangeAccessor = R.curry((data, column) => {
|
||||||
|
const accessor = getTableCellValueAccessor(column.cell_index);
|
||||||
|
const width = getReportColWidth(data, accessor, column.label);
|
||||||
|
|
||||||
|
return {
|
||||||
|
Header: column.label,
|
||||||
|
key: column.key,
|
||||||
|
accessor,
|
||||||
|
width,
|
||||||
|
align: Align.Right,
|
||||||
|
disableSortBy: true,
|
||||||
|
textOverview: true,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Previous period percentage column accessor.
|
||||||
|
*/
|
||||||
|
const previousPeriodPercentageAccessor = R.curry((data, column) => {
|
||||||
|
const accessor = getTableCellValueAccessor(column.cell_index);
|
||||||
|
const width = getReportColWidth(data, accessor, column.label);
|
||||||
|
|
||||||
|
return {
|
||||||
|
Header: column.label,
|
||||||
|
key: column.key,
|
||||||
|
accessor,
|
||||||
|
width,
|
||||||
|
align: Align.Right,
|
||||||
|
disableSortBy: true,
|
||||||
|
textOverview: true,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} column
|
||||||
|
* @param {*} index
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
const totalColumnsMapper = R.curry((data, column) => {
|
||||||
|
return R.compose(
|
||||||
|
R.when(R.pathEq(['key'], 'total'), totalMapper(data)),
|
||||||
|
// Percetage of column/row.
|
||||||
|
R.when(
|
||||||
|
R.pathEq(['key'], 'percentage_of_column'),
|
||||||
|
percentageOfColumnAccessor(data),
|
||||||
|
),
|
||||||
|
R.when(
|
||||||
|
R.pathEq(['key'], 'percentage_of_row'),
|
||||||
|
percentageOfRowAccessor(data),
|
||||||
|
),
|
||||||
|
// Previous year.
|
||||||
|
R.when(R.pathEq(['key'], 'previous_year'), previousYearAccessor(data)),
|
||||||
|
R.when(
|
||||||
|
R.pathEq(['key'], 'previous_year_change'),
|
||||||
|
previousYearChangeAccessor(data),
|
||||||
|
),
|
||||||
|
R.when(
|
||||||
|
R.pathEq(['key'], 'previous_year_percentage'),
|
||||||
|
previousYearPercentageAccessor(data),
|
||||||
|
),
|
||||||
|
// Pervious period.
|
||||||
|
R.when(R.pathEq(['key'], 'previous_period'), previousPeriodAccessor(data)),
|
||||||
|
R.when(
|
||||||
|
R.pathEq(['key'], 'previous_period_change'),
|
||||||
|
previousPeriodChangeAccessor(data),
|
||||||
|
),
|
||||||
|
R.when(
|
||||||
|
R.pathEq(['key'], 'previous_period_percentage'),
|
||||||
|
previousPeriodPercentageAccessor(data),
|
||||||
|
),
|
||||||
|
)(column);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total sub-columns composer.
|
||||||
|
*/
|
||||||
|
const totalColumnsComposer = R.curry((data, column) => {
|
||||||
|
return R.map(totalColumnsMapper(data), column.children);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detarmines the given string starts with `date-range` string.
|
||||||
|
*/
|
||||||
|
const isMatchesDateRange = (r) => R.match(/^date-range/g, r).length > 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dynamic column mapper.
|
||||||
|
*/
|
||||||
|
const dynamicColumnMapper = R.curry((data, column) => {
|
||||||
|
const indexTotalMapper = totalMapper(data);
|
||||||
|
const indexAccountNameMapper = accountNameMapper(data);
|
||||||
|
const indexDatePeriodMapper = dateRangeMapper(data);
|
||||||
|
|
||||||
|
return R.compose(
|
||||||
|
R.when(R.pathSatisfies(isMatchesDateRange, ['key']), indexDatePeriodMapper),
|
||||||
|
R.when(R.pathEq(['key'], 'name'), indexAccountNameMapper),
|
||||||
|
R.when(R.pathEq(['key'], 'total'), indexTotalMapper),
|
||||||
|
)(column);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cash flow dynamic columns.
|
||||||
|
*/
|
||||||
|
export const dynamicColumns = (columns, data) => {
|
||||||
|
return R.map(dynamicColumnMapper(data), columns);
|
||||||
|
};
|
||||||
@@ -1,7 +1,63 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import * as R from 'ramda';
|
||||||
|
import moment from 'moment';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import moment from 'moment';
|
|
||||||
|
|
||||||
|
import { transformToForm } from 'utils';
|
||||||
|
import { useAppQueryString } from 'hooks';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the default balance sheet query.
|
||||||
|
* @returns {}
|
||||||
|
*/
|
||||||
|
export const getDefaultBalanceSheetQuery = () => ({
|
||||||
|
fromDate: moment().startOf('year').format('YYYY-MM-DD'),
|
||||||
|
toDate: moment().endOf('year').format('YYYY-MM-DD'),
|
||||||
|
basis: 'cash',
|
||||||
|
displayColumnsType: 'total',
|
||||||
|
filterByOption: 'without-zero-balance',
|
||||||
|
|
||||||
|
previousYear: false,
|
||||||
|
previousYearAmountChange: false,
|
||||||
|
previousYearPercentageChange: false,
|
||||||
|
|
||||||
|
previousPeriod: false,
|
||||||
|
previousPeriodAmountChange: false,
|
||||||
|
previousPeriodPercentageChange: false,
|
||||||
|
|
||||||
|
// Percentage columns.
|
||||||
|
percentageOfColumn: false,
|
||||||
|
percentageOfRow: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the balance sheet query.
|
||||||
|
*/
|
||||||
|
export const useBalanceSheetQuery = () => {
|
||||||
|
// Retrieves location query.
|
||||||
|
const [locationQuery, setLocationQuery] = useAppQueryString();
|
||||||
|
|
||||||
|
// Merges the default filter query with location URL query.
|
||||||
|
const query = React.useMemo(() => {
|
||||||
|
const defaultQuery = getDefaultBalanceSheetQuery();
|
||||||
|
|
||||||
|
return {
|
||||||
|
...defaultQuery,
|
||||||
|
...transformToForm(locationQuery, defaultQuery),
|
||||||
|
};
|
||||||
|
}, [locationQuery]);
|
||||||
|
|
||||||
|
return {
|
||||||
|
query,
|
||||||
|
locationQuery,
|
||||||
|
setLocationQuery,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the balance sheet header default values.
|
||||||
|
*/
|
||||||
export const getBalanceSheetHeaderDefaultValues = () => {
|
export const getBalanceSheetHeaderDefaultValues = () => {
|
||||||
return {
|
return {
|
||||||
basic: 'cash',
|
basic: 'cash',
|
||||||
@@ -12,6 +68,9 @@ export const getBalanceSheetHeaderDefaultValues = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the balance sheet header validation schema.
|
||||||
|
*/
|
||||||
export const getBalanceSheetHeaderValidationSchema = () =>
|
export const getBalanceSheetHeaderValidationSchema = () =>
|
||||||
Yup.object().shape({
|
Yup.object().shape({
|
||||||
dateRange: Yup.string().optional(),
|
dateRange: Yup.string().optional(),
|
||||||
@@ -23,3 +82,83 @@ export const getBalanceSheetHeaderValidationSchema = () =>
|
|||||||
filterByOption: Yup.string(),
|
filterByOption: Yup.string(),
|
||||||
displayColumnsType: Yup.string(),
|
displayColumnsType: Yup.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles previous year checkbox change.
|
||||||
|
*/
|
||||||
|
export const handlePreviousYearCheckBoxChange = R.curry((form, event) => {
|
||||||
|
const isChecked = event.currentTarget.checked;
|
||||||
|
form.setFieldValue('previousYear', isChecked);
|
||||||
|
|
||||||
|
if (!isChecked) {
|
||||||
|
form.setFieldValue('previousYearAmountChange', isChecked);
|
||||||
|
form.setFieldValue('previousYearPercentageChange', isChecked);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles previous period checkbox change.
|
||||||
|
*/
|
||||||
|
export const handlePreviousPeriodCheckBoxChange = R.curry((form, event) => {
|
||||||
|
const isChecked = event.currentTarget.checked;
|
||||||
|
form.setFieldValue('previousPeriod', isChecked);
|
||||||
|
|
||||||
|
if (!isChecked) {
|
||||||
|
form.setFieldValue('previousPeriodAmountChange', isChecked);
|
||||||
|
form.setFieldValue('previousPeriodPercentageChange', isChecked);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles previous year change checkbox change.
|
||||||
|
*/
|
||||||
|
export const handlePreviousYearChangeCheckboxChange = R.curry((form, event) => {
|
||||||
|
const isChecked = event.currentTarget.checked;
|
||||||
|
|
||||||
|
if (isChecked) {
|
||||||
|
form.setFieldValue('previousYear', event.currentTarget.checked);
|
||||||
|
}
|
||||||
|
form.setFieldValue('previousYearAmountChange', event.currentTarget.checked);
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles preivous year percentage checkbox change.
|
||||||
|
*/
|
||||||
|
export const handlePreviousYearPercentageCheckboxChange = R.curry(
|
||||||
|
(form, event) => {
|
||||||
|
const isChecked = event.currentTarget.checked;
|
||||||
|
|
||||||
|
if (isChecked) {
|
||||||
|
form.setFieldValue('previousYear', event.currentTarget.checked);
|
||||||
|
}
|
||||||
|
form.setFieldValue('previousYearPercentageChange', isChecked);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handles previous period percentage checkbox change.
|
||||||
|
*/
|
||||||
|
export const handlePreivousPeriodPercentageCheckboxChange = R.curry(
|
||||||
|
(form, event) => {
|
||||||
|
const isChecked = event.currentTarget.checked;
|
||||||
|
|
||||||
|
if (isChecked) {
|
||||||
|
form.setFieldValue('previousPeriod', isChecked);
|
||||||
|
}
|
||||||
|
form.setFieldValue('previousPeriodPercentageChange', isChecked);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handle previous period change checkbox change.
|
||||||
|
*/
|
||||||
|
export const handlePreviousPeriodChangeCheckboxChange = R.curry(
|
||||||
|
(form, event) => {
|
||||||
|
const isChecked = event.currentTarget.checked;
|
||||||
|
|
||||||
|
if (isChecked) {
|
||||||
|
form.setFieldValue('previousPeriod', isChecked);
|
||||||
|
}
|
||||||
|
form.setFieldValue('previousPeriodAmountChange', isChecked);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|||||||
@@ -1,15 +1,13 @@
|
|||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect } from 'react';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import 'style/pages/FinancialStatements/CashFlowStatement.scss';
|
|
||||||
|
|
||||||
import { FinancialStatement } from 'components';
|
import { FinancialStatement } from 'components';
|
||||||
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||||
|
|
||||||
import CashFlowStatementHeader from './CashFlowStatementHeader';
|
import CashFlowStatementHeader from './CashFlowStatementHeader';
|
||||||
import CashFlowStatementTable from './CashFlowStatementTable';
|
|
||||||
import CashFlowStatementActionsBar from './CashFlowStatementActionsBar';
|
import CashFlowStatementActionsBar from './CashFlowStatementActionsBar';
|
||||||
|
import { CashFlowStatementBody } from './CashFlowStatementBody';
|
||||||
|
|
||||||
import withCurrentOrganization from '../../Organization/withCurrentOrganization';
|
|
||||||
import withCashFlowStatementActions from './withCashFlowStatementActions';
|
import withCashFlowStatementActions from './withCashFlowStatementActions';
|
||||||
import { CashFlowStatementProvider } from './CashFlowStatementProvider';
|
import { CashFlowStatementProvider } from './CashFlowStatementProvider';
|
||||||
import {
|
import {
|
||||||
@@ -17,26 +15,20 @@ import {
|
|||||||
CashFlowStatementAlerts,
|
CashFlowStatementAlerts,
|
||||||
} from './components';
|
} from './components';
|
||||||
|
|
||||||
|
import { getDefaultCashFlowSheetQuery } from './utils';
|
||||||
import { compose } from 'utils';
|
import { compose } from 'utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cash flow statement.
|
* Cash flow statement.
|
||||||
*/
|
*/
|
||||||
function CashFlowStatement({
|
function CashFlowStatement({
|
||||||
// #withPreferences
|
|
||||||
organizationName,
|
|
||||||
//#withCashStatementActions
|
//#withCashStatementActions
|
||||||
toggleCashFlowStatementFilterDrawer,
|
toggleCashFlowStatementFilterDrawer,
|
||||||
}) {
|
}) {
|
||||||
// filter
|
// filter
|
||||||
const [filter, setFilter] = useState({
|
const [filter, setFilter] = useState({
|
||||||
fromDate: moment().startOf('year').format('YYYY-MM-DD'),
|
...getDefaultCashFlowSheetQuery(),
|
||||||
toDate: moment().endOf('year').format('YYYY-MM-DD'),
|
|
||||||
basis: 'cash',
|
|
||||||
displayColumnsType: 'total',
|
|
||||||
filterByOption: 'with-transactions',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle refetch cash flow after filter change.
|
// Handle refetch cash flow after filter change.
|
||||||
const handleFilterSubmit = (filter) => {
|
const handleFilterSubmit = (filter) => {
|
||||||
const _filter = {
|
const _filter = {
|
||||||
@@ -46,7 +38,6 @@ function CashFlowStatement({
|
|||||||
};
|
};
|
||||||
setFilter({ ..._filter });
|
setFilter({ ..._filter });
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle format number submit.
|
// Handle format number submit.
|
||||||
const handleNumberFormatSubmit = (values) => {
|
const handleNumberFormatSubmit = (values) => {
|
||||||
setFilter({
|
setFilter({
|
||||||
@@ -70,24 +61,18 @@ function CashFlowStatement({
|
|||||||
/>
|
/>
|
||||||
<CashFlowStatementLoadingBar />
|
<CashFlowStatementLoadingBar />
|
||||||
<CashFlowStatementAlerts />
|
<CashFlowStatementAlerts />
|
||||||
|
|
||||||
<DashboardPageContent>
|
<DashboardPageContent>
|
||||||
<FinancialStatement>
|
<FinancialStatement>
|
||||||
<CashFlowStatementHeader
|
<CashFlowStatementHeader
|
||||||
pageFilter={filter}
|
pageFilter={filter}
|
||||||
onSubmitFilter={handleFilterSubmit}
|
onSubmitFilter={handleFilterSubmit}
|
||||||
/>
|
/>
|
||||||
<div class="financial-statement__body">
|
<CashFlowStatementBody />
|
||||||
<CashFlowStatementTable companyName={organizationName} />
|
|
||||||
</div>
|
|
||||||
</FinancialStatement>
|
</FinancialStatement>
|
||||||
</DashboardPageContent>
|
</DashboardPageContent>
|
||||||
</CashFlowStatementProvider>
|
</CashFlowStatementProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default compose(
|
export default compose(withCashFlowStatementActions)(CashFlowStatement);
|
||||||
withCurrentOrganization(({ organization }) => ({
|
|
||||||
organizationName: organization.name,
|
|
||||||
})),
|
|
||||||
withCashFlowStatementActions,
|
|
||||||
)(CashFlowStatement);
|
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import * as R from 'ramda';
|
||||||
|
|
||||||
|
import CashFlowStatementTable from './CashFlowStatementTable';
|
||||||
|
import { FinancialReportBody } from '../FinancialReportPage';
|
||||||
|
import { FinancialSheetSkeleton } from 'components/FinancialSheet';
|
||||||
|
|
||||||
|
import { useCashFlowStatementContext } from './CashFlowStatementProvider';
|
||||||
|
import withCurrentOrganization from '../../Organization/withCurrentOrganization';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cashflow stement body.
|
||||||
|
* @returns {React.JSX}
|
||||||
|
*/
|
||||||
|
function CashFlowStatementBodyJSX({
|
||||||
|
// #withPreferences
|
||||||
|
organizationName,
|
||||||
|
}) {
|
||||||
|
const { isCashFlowLoading } = useCashFlowStatementContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FinancialReportBody>
|
||||||
|
{isCashFlowLoading ? (
|
||||||
|
<FinancialSheetSkeleton />
|
||||||
|
) : (
|
||||||
|
<CashFlowStatementTable companyName={organizationName} />
|
||||||
|
)}
|
||||||
|
</FinancialReportBody>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CashFlowStatementBody = R.compose(
|
||||||
|
withCurrentOrganization(({ organization }) => ({
|
||||||
|
organizationName: organization.name,
|
||||||
|
})),
|
||||||
|
)(CashFlowStatementBodyJSX);
|
||||||
@@ -12,6 +12,7 @@ import CashFlowStatementGeneralPanel from './CashFlowStatementGeneralPanel';
|
|||||||
import withCashFlowStatement from './withCashFlowStatement';
|
import withCashFlowStatement from './withCashFlowStatement';
|
||||||
import withCashFlowStatementActions from './withCashFlowStatementActions';
|
import withCashFlowStatementActions from './withCashFlowStatementActions';
|
||||||
|
|
||||||
|
import { getDefaultCashFlowSheetQuery } from './utils';
|
||||||
import { compose, transformToForm } from 'utils';
|
import { compose, transformToForm } from 'utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -29,10 +30,7 @@ function CashFlowStatementHeader({
|
|||||||
toggleCashFlowStatementFilterDrawer,
|
toggleCashFlowStatementFilterDrawer,
|
||||||
}) {
|
}) {
|
||||||
// Filter form default values.
|
// Filter form default values.
|
||||||
const defaultValues = {
|
const defaultValues = getDefaultCashFlowSheetQuery();
|
||||||
fromDate: moment().toDate(),
|
|
||||||
toDate: moment().toDate(),
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initial form values.
|
// Initial form values.
|
||||||
const initialValues = transformToForm({
|
const initialValues = transformToForm({
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
import { DataTable, FinancialSheet } from 'components';
|
||||||
|
|
||||||
import { DataTable } from 'components';
|
|
||||||
import FinancialSheet from 'components/FinancialSheet';
|
|
||||||
import { useCashFlowStatementColumns } from './components';
|
import { useCashFlowStatementColumns } from './components';
|
||||||
import { useCashFlowStatementContext } from './CashFlowStatementProvider';
|
import { useCashFlowStatementContext } from './CashFlowStatementProvider';
|
||||||
|
|
||||||
import { defaultExpanderReducer } from 'utils';
|
import { TableStyle } from 'common';
|
||||||
|
import { defaultExpanderReducer, tableRowTypesToClassnames } from 'utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cash flow statement table.
|
* Cash flow statement table.
|
||||||
@@ -15,11 +17,8 @@ export default function CashFlowStatementTable({
|
|||||||
// #ownProps
|
// #ownProps
|
||||||
companyName,
|
companyName,
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
cashFlowStatement: { tableRows },
|
cashFlowStatement: { tableRows },
|
||||||
isCashFlowLoading,
|
|
||||||
query,
|
query,
|
||||||
} = useCashFlowStatementContext();
|
} = useCashFlowStatementContext();
|
||||||
|
|
||||||
@@ -29,35 +28,63 @@ export default function CashFlowStatementTable({
|
|||||||
() => defaultExpanderReducer(tableRows, 4),
|
() => defaultExpanderReducer(tableRows, 4),
|
||||||
[tableRows],
|
[tableRows],
|
||||||
);
|
);
|
||||||
|
|
||||||
const rowClassNames = (row) => {
|
|
||||||
return [
|
|
||||||
`row-type--${row.original.row_types}`,
|
|
||||||
`row-type--${row.original.id}`,
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FinancialSheet
|
<FinancialSheet
|
||||||
name="cash-flow-statement"
|
|
||||||
companyName={companyName}
|
companyName={companyName}
|
||||||
sheetType={intl.get('statement_of_cash_flow')}
|
sheetType={intl.get('statement_of_cash_flow')}
|
||||||
loading={isCashFlowLoading}
|
|
||||||
fromDate={query.from_date}
|
fromDate={query.from_date}
|
||||||
toDate={query.to_date}
|
toDate={query.to_date}
|
||||||
basis={query.basis}
|
basis={query.basis}
|
||||||
>
|
>
|
||||||
<DataTable
|
<CashflowStatementDataTable
|
||||||
className="bigcapital-datatable--financial-report"
|
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={tableRows}
|
data={tableRows}
|
||||||
rowClassNames={rowClassNames}
|
rowClassNames={tableRowTypesToClassnames}
|
||||||
noInitialFetch={true}
|
noInitialFetch={true}
|
||||||
expandable={true}
|
expandable={true}
|
||||||
expanded={expandedRows}
|
expanded={expandedRows}
|
||||||
expandToggleColumn={1}
|
expandToggleColumn={1}
|
||||||
expandColumnSpace={0.8}
|
expandColumnSpace={0.8}
|
||||||
|
styleName={TableStyle.Constrant}
|
||||||
/>
|
/>
|
||||||
</FinancialSheet>
|
</FinancialSheet>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CashflowStatementDataTable = styled(DataTable)`
|
||||||
|
.table {
|
||||||
|
.tbody {
|
||||||
|
.tr:not(.no-results) {
|
||||||
|
.td {
|
||||||
|
border-bottom: 0;
|
||||||
|
padding-top: 0.32rem;
|
||||||
|
padding-bottom: 0.32rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
// &.row-type--AGGREGATE,
|
||||||
|
&.row_type--ACCOUNTS {
|
||||||
|
border-top: 1px solid #bbb;
|
||||||
|
}
|
||||||
|
&.row-id--CASH_END_PERIOD {
|
||||||
|
border-bottom: 3px double #333;
|
||||||
|
}
|
||||||
|
&.row_type--TOTAL {
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
&:not(:first-child) .td {
|
||||||
|
border-top: 1px solid #bbb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.tr.is-expanded {
|
||||||
|
.td.total,
|
||||||
|
.td.date-period {
|
||||||
|
.cell-inner {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Button } from '@blueprintjs/core';
|
import { Button } from '@blueprintjs/core';
|
||||||
|
|
||||||
import { Icon, If } from 'components';
|
import { Icon, If } from 'components';
|
||||||
import { FormattedMessage as T } from 'components';
|
import { FormattedMessage as T } from 'components';
|
||||||
|
|
||||||
import { dynamicColumns } from './utils';
|
|
||||||
import { useCashFlowStatementContext } from './CashFlowStatementProvider';
|
|
||||||
import FinancialLoadingBar from '../FinancialLoadingBar';
|
import FinancialLoadingBar from '../FinancialLoadingBar';
|
||||||
|
|
||||||
|
import { dynamicColumns } from './dynamicColumns';
|
||||||
|
import { useCashFlowStatementContext } from './CashFlowStatementProvider';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve cash flow statement columns.
|
* Retrieve cash flow statement columns.
|
||||||
*/
|
*/
|
||||||
@@ -49,7 +50,6 @@ export function CashFlowStatementAlerts() {
|
|||||||
if (isCashFlowLoading) {
|
if (isCashFlowLoading) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<If condition={cashFlowStatement.meta.is_cost_compute_running}>
|
<If condition={cashFlowStatement.meta.is_cost_compute_running}>
|
||||||
<div className="alert-compute-running">
|
<div className="alert-compute-running">
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
import * as R from 'ramda';
|
||||||
|
import intl from 'react-intl-universal';
|
||||||
|
|
||||||
|
import { Align } from 'common';
|
||||||
|
import { CellTextSpan } from 'components/Datatable/Cells';
|
||||||
|
import { getColumnWidth } from 'utils';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Account name column mapper.
|
||||||
|
*/
|
||||||
|
const accountNameMapper = (column) => ({
|
||||||
|
id: column.key,
|
||||||
|
key: column.key,
|
||||||
|
Header: intl.get('account_name'),
|
||||||
|
accessor: 'cells[0].value',
|
||||||
|
className: 'account_name',
|
||||||
|
textOverview: true,
|
||||||
|
width: 400,
|
||||||
|
disableSortBy: true,
|
||||||
|
sticky: Align.Left,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Date range columns mapper.
|
||||||
|
*/
|
||||||
|
const dateRangeMapper = (data, index, column) => ({
|
||||||
|
id: column.key,
|
||||||
|
Header: column.label,
|
||||||
|
key: column.key,
|
||||||
|
accessor: `cells[${index}].value`,
|
||||||
|
width: getColumnWidth(data, `cells.${index}.value`, {
|
||||||
|
magicSpacing: 10,
|
||||||
|
minWidth: 100,
|
||||||
|
}),
|
||||||
|
className: `date-period ${column.key}`,
|
||||||
|
disableSortBy: true,
|
||||||
|
textOverview: true,
|
||||||
|
align: Align.Right,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Total column mapper.
|
||||||
|
*/
|
||||||
|
const totalMapper = (data, index, column) => ({
|
||||||
|
key: 'total',
|
||||||
|
Header: intl.get('total'),
|
||||||
|
accessor: `cells[${index}].value`,
|
||||||
|
className: 'total',
|
||||||
|
textOverview: true,
|
||||||
|
Cell: CellTextSpan,
|
||||||
|
width: getColumnWidth(data, `cells[${index}].value`, {
|
||||||
|
magicSpacing: 10,
|
||||||
|
minWidth: 100,
|
||||||
|
}),
|
||||||
|
disableSortBy: true,
|
||||||
|
align: Align.Right,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detarmines the given string starts with `date-range` string.
|
||||||
|
*/
|
||||||
|
const isMatchesDateRange = (r) => R.match(/^date-range/g, r).length > 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cash flow dynamic columns.
|
||||||
|
*/
|
||||||
|
export const dynamicColumns = (columns, data) => {
|
||||||
|
const mapper = (column, index) => {
|
||||||
|
return R.compose(
|
||||||
|
R.when(
|
||||||
|
R.pathSatisfies(isMatchesDateRange, ['key']),
|
||||||
|
R.curry(dateRangeMapper)(data, index),
|
||||||
|
),
|
||||||
|
R.when(R.pathEq(['key'], 'name'), accountNameMapper),
|
||||||
|
R.when(R.pathEq(['key'], 'total'), R.curry(totalMapper)(data, index)),
|
||||||
|
)(column);
|
||||||
|
};
|
||||||
|
return columns.map(mapper);
|
||||||
|
};
|
||||||
@@ -1,74 +1,14 @@
|
|||||||
import * as R from 'ramda';
|
import moment from 'moment';
|
||||||
import { CellTextSpan } from 'components/Datatable/Cells';
|
|
||||||
import { getColumnWidth } from 'utils';
|
|
||||||
import intl from 'react-intl-universal';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Account name column mapper.
|
* Retrieves the default cashflow sheet query.
|
||||||
*/
|
*/
|
||||||
const accountNameMapper = (column) => ({
|
export const getDefaultCashFlowSheetQuery = () => {
|
||||||
id: column.key,
|
return {
|
||||||
key: column.key,
|
fromDate: moment().startOf('year').format('YYYY-MM-DD'),
|
||||||
Header: intl.get('account_name'),
|
toDate: moment().endOf('year').format('YYYY-MM-DD'),
|
||||||
accessor: 'cells[0].value',
|
basis: 'cash',
|
||||||
className: 'account_name',
|
displayColumnsType: 'total',
|
||||||
textOverview: true,
|
filterByOption: 'with-transactions',
|
||||||
width: 400,
|
|
||||||
disableSortBy: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Date range columns mapper.
|
|
||||||
*/
|
|
||||||
const dateRangeMapper = (data, index, column) => ({
|
|
||||||
id: column.key,
|
|
||||||
Header: column.label,
|
|
||||||
key: column.key,
|
|
||||||
accessor: `cells[${index}].value`,
|
|
||||||
width: getColumnWidth(data, `cells.${index}.value`, {
|
|
||||||
magicSpacing: 10,
|
|
||||||
minWidth: 100,
|
|
||||||
}),
|
|
||||||
className: `date-period ${column.key}`,
|
|
||||||
disableSortBy: true,
|
|
||||||
textOverview: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Total column mapper.
|
|
||||||
*/
|
|
||||||
const totalMapper = (data, index, column) => ({
|
|
||||||
key: 'total',
|
|
||||||
Header: intl.get('total'),
|
|
||||||
accessor: `cells[${index}].value`,
|
|
||||||
className: 'total',
|
|
||||||
textOverview: true,
|
|
||||||
Cell: CellTextSpan,
|
|
||||||
width: getColumnWidth(data, `cells[${index}].value`, {
|
|
||||||
magicSpacing: 10,
|
|
||||||
minWidth: 100,
|
|
||||||
}),
|
|
||||||
disableSortBy: true,
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Detarmines the given string starts with `date-range` string.
|
|
||||||
*/
|
|
||||||
const isMatchesDateRange = (r) => R.match(/^date-range/g, r).length > 0;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Cash flow dynamic columns.
|
|
||||||
*/
|
|
||||||
export const dynamicColumns = (columns, data) => {
|
|
||||||
const mapper = (column, index) => {
|
|
||||||
return R.compose(
|
|
||||||
R.when(
|
|
||||||
R.pathSatisfies(isMatchesDateRange, ['key']),
|
|
||||||
R.curry(dateRangeMapper)(data, index),
|
|
||||||
),
|
|
||||||
R.when(R.pathEq(['key'], 'name'), accountNameMapper),
|
|
||||||
R.when(R.pathEq(['key'], 'total'), R.curry(totalMapper)(data, index)),
|
|
||||||
)(column);
|
|
||||||
};
|
};
|
||||||
return columns.map(mapper);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import * as R from 'ramda';
|
||||||
|
|
||||||
|
import { FinancialReportBody } from '../FinancialReportPage';
|
||||||
|
import CustomersBalanceSummaryTable from './CustomersBalanceSummaryTable';
|
||||||
|
import { FinancialSheetSkeleton } from '../../../components/FinancialSheet';
|
||||||
|
import { useCustomersBalanceSummaryContext } from './CustomersBalanceSummaryProvider';
|
||||||
|
import withCurrentOrganization from '../../Organization/withCurrentOrganization';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customer balance summary body.
|
||||||
|
* @returns {JSX.Element}
|
||||||
|
*/
|
||||||
|
function CustomerBalanceSummaryBodyJSX({
|
||||||
|
// #withPreferences
|
||||||
|
organizationName,
|
||||||
|
}) {
|
||||||
|
const { isCustomersBalanceLoading } = useCustomersBalanceSummaryContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FinancialReportBody>
|
||||||
|
{isCustomersBalanceLoading ? (
|
||||||
|
<FinancialSheetSkeleton />
|
||||||
|
) : (
|
||||||
|
<CustomersBalanceSummaryTable companyName={organizationName} />
|
||||||
|
)}
|
||||||
|
</FinancialReportBody>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CustomerBalanceSummaryBody = R.compose(
|
||||||
|
withCurrentOrganization(({ organization }) => ({
|
||||||
|
organizationName: organization.name,
|
||||||
|
})),
|
||||||
|
)(CustomerBalanceSummaryBodyJSX);
|
||||||
@@ -1,37 +1,30 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
|
import * as R from 'ramda';
|
||||||
import 'style/pages/FinancialStatements/ContactsBalanceSummary.scss';
|
|
||||||
|
|
||||||
import { FinancialStatement } from 'components';
|
import { FinancialStatement } from 'components';
|
||||||
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||||
|
|
||||||
import CustomersBalanceSummaryActionsBar from './CustomersBalanceSummaryActionsBar';
|
import CustomersBalanceSummaryActionsBar from './CustomersBalanceSummaryActionsBar';
|
||||||
import CustomersBalanceSummaryHeader from './CustomersBalanceSummaryHeader';
|
import CustomersBalanceSummaryHeader from './CustomersBalanceSummaryHeader';
|
||||||
import CustomersBalanceSummaryTable from './CustomersBalanceSummaryTable';
|
|
||||||
|
|
||||||
|
import { CustomerBalanceSummaryBody } from './CustomerBalanceSummaryBody';
|
||||||
import { CustomersBalanceLoadingBar } from './components';
|
import { CustomersBalanceLoadingBar } from './components';
|
||||||
import { CustomersBalanceSummaryProvider } from './CustomersBalanceSummaryProvider';
|
import { CustomersBalanceSummaryProvider } from './CustomersBalanceSummaryProvider';
|
||||||
import withCustomersBalanceSummaryActions from './withCustomersBalanceSummaryActions';
|
import withCustomersBalanceSummaryActions from './withCustomersBalanceSummaryActions';
|
||||||
import withCurrentOrganization from '../../Organization/withCurrentOrganization';
|
|
||||||
|
|
||||||
import { compose } from 'redux';
|
import { getDefaultCustomersBalanceQuery } from './utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Customers Balance summary.
|
* Customers Balance summary.
|
||||||
*/
|
*/
|
||||||
function CustomersBalanceSummary({
|
function CustomersBalanceSummary({
|
||||||
// #withPreferences
|
|
||||||
organizationName,
|
|
||||||
|
|
||||||
// #withCustomersBalanceSummaryActions
|
// #withCustomersBalanceSummaryActions
|
||||||
toggleCustomerBalanceFilterDrawer,
|
toggleCustomerBalanceFilterDrawer,
|
||||||
}) {
|
}) {
|
||||||
const [filter, setFilter] = useState({
|
const [filter, setFilter] = useState({
|
||||||
asDate: moment().endOf('day').format('YYYY-MM-DD'),
|
...getDefaultCustomersBalanceQuery(),
|
||||||
filterByOption: 'with-transactions',
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Handle re-fetch customers balance summary after filter change.
|
// Handle re-fetch customers balance summary after filter change.
|
||||||
const handleFilterSubmit = (filter) => {
|
const handleFilterSubmit = (filter) => {
|
||||||
const _filter = {
|
const _filter = {
|
||||||
@@ -40,7 +33,6 @@ function CustomersBalanceSummary({
|
|||||||
};
|
};
|
||||||
setFilter({ ..._filter });
|
setFilter({ ..._filter });
|
||||||
};
|
};
|
||||||
|
|
||||||
// Handle number format.
|
// Handle number format.
|
||||||
const handleNumberFormat = (values) => {
|
const handleNumberFormat = (values) => {
|
||||||
setFilter({
|
setFilter({
|
||||||
@@ -66,23 +58,16 @@ function CustomersBalanceSummary({
|
|||||||
|
|
||||||
<DashboardPageContent>
|
<DashboardPageContent>
|
||||||
<FinancialStatement>
|
<FinancialStatement>
|
||||||
<div className="financial-statement--balance-summary ">
|
<CustomersBalanceSummaryHeader
|
||||||
<CustomersBalanceSummaryHeader
|
pageFilter={filter}
|
||||||
pageFilter={filter}
|
onSubmitFilter={handleFilterSubmit}
|
||||||
onSubmitFilter={handleFilterSubmit}
|
/>
|
||||||
/>
|
<CustomerBalanceSummaryBody />
|
||||||
<div className="financial-statement__body">
|
|
||||||
<CustomersBalanceSummaryTable companyName={organizationName} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</FinancialStatement>
|
</FinancialStatement>
|
||||||
</DashboardPageContent>
|
</DashboardPageContent>
|
||||||
</CustomersBalanceSummaryProvider>
|
</CustomersBalanceSummaryProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default compose(
|
export default R.compose(withCustomersBalanceSummaryActions)(
|
||||||
withCurrentOrganization(({ organization }) => ({
|
CustomersBalanceSummary,
|
||||||
organizationName: organization.name,
|
);
|
||||||
})),
|
|
||||||
withCustomersBalanceSummaryActions,
|
|
||||||
)(CustomersBalanceSummary);
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ export default function CustomersBalanceSummaryGeneralPanelContent() {
|
|||||||
|
|
||||||
<Row>
|
<Row>
|
||||||
<Col xs={5}>
|
<Col xs={5}>
|
||||||
<FastField name={'percentage'} type={'checkbox'}>
|
<FastField name={'percentage_column'} type={'checkbox'}>
|
||||||
{({ field }) => (
|
{({ field }) => (
|
||||||
<FormGroup labelInfo={<FieldHint />}>
|
<FormGroup labelInfo={<FieldHint />}>
|
||||||
<Checkbox
|
<Checkbox
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ import * as Yup from 'yup';
|
|||||||
import { Formik, Form } from 'formik';
|
import { Formik, Form } from 'formik';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import { Tabs, Tab, Button, Intent } from '@blueprintjs/core';
|
import { Tabs, Tab, Button, Intent } from '@blueprintjs/core';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import { FormattedMessage as T } from 'components';
|
import { FormattedMessage as T } from 'components';
|
||||||
|
|
||||||
import FinancialStatementHeader from 'containers/FinancialStatements/FinancialStatementHeader';
|
import FinancialStatementHeader from 'containers/FinancialStatements/FinancialStatementHeader';
|
||||||
@@ -30,7 +32,6 @@ function CustomersBalanceSummaryHeader({
|
|||||||
const validationSchema = Yup.object().shape({
|
const validationSchema = Yup.object().shape({
|
||||||
asDate: Yup.date().required().label('asDate'),
|
asDate: Yup.date().required().label('asDate'),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Default form values.
|
// Default form values.
|
||||||
const defaultValues = {
|
const defaultValues = {
|
||||||
...pageFilter,
|
...pageFilter,
|
||||||
@@ -47,21 +48,19 @@ function CustomersBalanceSummaryHeader({
|
|||||||
},
|
},
|
||||||
defaultValues,
|
defaultValues,
|
||||||
);
|
);
|
||||||
|
|
||||||
// handle form submit.
|
// handle form submit.
|
||||||
const handleSubmit = (values, { setSubmitting }) => {
|
const handleSubmit = (values, { setSubmitting }) => {
|
||||||
onSubmitFilter(values);
|
onSubmitFilter(values);
|
||||||
toggleCustomerBalanceFilterDrawer(false);
|
toggleCustomerBalanceFilterDrawer(false);
|
||||||
setSubmitting(false);
|
setSubmitting(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
// handle close drawer.
|
// handle close drawer.
|
||||||
const handleDrawerClose = () => {
|
const handleDrawerClose = () => {
|
||||||
toggleCustomerBalanceFilterDrawer(false);
|
toggleCustomerBalanceFilterDrawer(false);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FinancialStatementHeader
|
<CustomerBalanceDrawerHeader
|
||||||
isOpen={customersBalanceDrawerFilter}
|
isOpen={customersBalanceDrawerFilter}
|
||||||
drawerProps={{ onClose: handleDrawerClose }}
|
drawerProps={{ onClose: handleDrawerClose }}
|
||||||
>
|
>
|
||||||
@@ -89,7 +88,7 @@ function CustomersBalanceSummaryHeader({
|
|||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
</Formik>
|
</Formik>
|
||||||
</FinancialStatementHeader>
|
</CustomerBalanceDrawerHeader>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,3 +98,9 @@ export default compose(
|
|||||||
})),
|
})),
|
||||||
withCustomersBalanceSummaryActions,
|
withCustomersBalanceSummaryActions,
|
||||||
)(CustomersBalanceSummaryHeader);
|
)(CustomersBalanceSummaryHeader);
|
||||||
|
|
||||||
|
const CustomerBalanceDrawerHeader = styled(FinancialStatementHeader)`
|
||||||
|
.bp3-drawer {
|
||||||
|
max-height: 450px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|||||||
@@ -1,48 +1,65 @@
|
|||||||
import React, { useMemo, useCallback } from 'react';
|
import React from 'react';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
import classNames from 'classnames';
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import FinancialSheet from 'components/FinancialSheet';
|
import { ReportDataTable, FinancialSheet } from 'components';
|
||||||
import DataTable from 'components/DataTable';
|
|
||||||
|
|
||||||
import { useCustomersBalanceSummaryContext } from './CustomersBalanceSummaryProvider';
|
import { useCustomersBalanceSummaryContext } from './CustomersBalanceSummaryProvider';
|
||||||
import { useCustomersSummaryColumns } from './components';
|
import { useCustomersSummaryColumns } from './components';
|
||||||
|
|
||||||
|
import { TableStyle } from 'common';
|
||||||
|
import { tableRowTypesToClassnames } from 'utils';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* customers balance summary table.
|
* Customers balance summary table.
|
||||||
*/
|
*/
|
||||||
export default function CustomersBalanceSummaryTable({
|
export default function CustomersBalanceSummaryTable({
|
||||||
// #ownProps
|
// #ownProps
|
||||||
companyName,
|
companyName,
|
||||||
}) {
|
}) {
|
||||||
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
isCustomersBalanceLoading,
|
CustomerBalanceSummary: { table },
|
||||||
CustomerBalanceSummary: { tableRows },
|
|
||||||
} = useCustomersBalanceSummaryContext();
|
} = useCustomersBalanceSummaryContext();
|
||||||
|
|
||||||
|
// Retrieves the customers summary columns.
|
||||||
const columns = useCustomersSummaryColumns();
|
const columns = useCustomersSummaryColumns();
|
||||||
|
|
||||||
const rowClassNames = (row) => {
|
|
||||||
return [`row-type--${row.original.row_types}`];
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FinancialSheet
|
<FinancialSheet
|
||||||
name={'customers-balance-summary'}
|
|
||||||
companyName={companyName}
|
companyName={companyName}
|
||||||
sheetType={intl.get('customers_balance_summary')}
|
sheetType={intl.get('customers_balance_summary')}
|
||||||
asDate={new Date()}
|
asDate={new Date()}
|
||||||
loading={isCustomersBalanceLoading}
|
|
||||||
>
|
>
|
||||||
<DataTable
|
<CustomerBalanceDataTable
|
||||||
className="bigcapital-datatable--financial-report"
|
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={tableRows}
|
data={table.data}
|
||||||
rowClassNames={rowClassNames}
|
rowClassNames={tableRowTypesToClassnames}
|
||||||
noInitialFetch={true}
|
noInitialFetch={true}
|
||||||
|
styleName={TableStyle.Constrant}
|
||||||
/>
|
/>
|
||||||
</FinancialSheet>
|
</FinancialSheet>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CustomerBalanceDataTable = styled(ReportDataTable)`
|
||||||
|
.table {
|
||||||
|
.tbody {
|
||||||
|
.tr:not(.no-results) {
|
||||||
|
.td {
|
||||||
|
border-bottom: 0;
|
||||||
|
padding-top: 0.4rem;
|
||||||
|
padding-bottom: 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.row_type--TOTAL {
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
.td {
|
||||||
|
border-top: 1px solid #bbb;
|
||||||
|
border-bottom: 3px double #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|||||||
@@ -1,37 +1,69 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
|
import * as R from 'ramda';
|
||||||
|
|
||||||
import { If } from 'components';
|
import { If } from 'components';
|
||||||
import FinancialLoadingBar from '../FinancialLoadingBar';
|
import FinancialLoadingBar from '../FinancialLoadingBar';
|
||||||
import { useCustomersBalanceSummaryContext } from './CustomersBalanceSummaryProvider';
|
import { useCustomersBalanceSummaryContext } from './CustomersBalanceSummaryProvider';
|
||||||
|
|
||||||
|
import { Align } from 'common';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve customers balance summary columns.
|
* Retrieve customers balance summary columns.
|
||||||
*/
|
*/
|
||||||
export const useCustomersSummaryColumns = () => {
|
export const useCustomersSummaryColumns = () => {
|
||||||
return React.useMemo(
|
const {
|
||||||
() => [
|
CustomerBalanceSummary: { table },
|
||||||
{
|
} = useCustomersBalanceSummaryContext();
|
||||||
Header: intl.get('customer_name'),
|
|
||||||
accessor: 'cells[0].value',
|
return React.useMemo(() => {
|
||||||
className: 'customer_name',
|
return dynamicColumns(table.columns || []);
|
||||||
width: 240,
|
}, [table.columns]);
|
||||||
},
|
};
|
||||||
{
|
|
||||||
Header: intl.get('total'),
|
/**
|
||||||
accessor: 'cells[1].value',
|
* Account name column accessor.
|
||||||
className: 'total',
|
*/
|
||||||
width: 140,
|
const accountNameColumnAccessor = () => ({
|
||||||
},
|
Header: intl.get('customer_name'),
|
||||||
{
|
accessor: 'cells[0].value',
|
||||||
Header: intl.get('percentage_of_column'),
|
className: 'customer_name',
|
||||||
accessor: 'cells[2].value',
|
width: 240,
|
||||||
className: 'total',
|
});
|
||||||
width: 140,
|
|
||||||
},
|
/**
|
||||||
],
|
* Total column accessor.
|
||||||
[],
|
*/
|
||||||
);
|
const totalColumnAccessor = () => ({
|
||||||
|
Header: intl.get('total'),
|
||||||
|
accessor: 'cells[1].value',
|
||||||
|
className: 'total',
|
||||||
|
width: 140,
|
||||||
|
align: Align.Right,
|
||||||
|
});
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Percentage column accessor.
|
||||||
|
*/
|
||||||
|
const percentageColumnAccessor = () => ({
|
||||||
|
Header: intl.get('percentage_of_column'),
|
||||||
|
accessor: 'cells[2].value',
|
||||||
|
className: 'total',
|
||||||
|
width: 140,
|
||||||
|
align: Align.Right,
|
||||||
|
});
|
||||||
|
|
||||||
|
const dynamicColumns = (columns) => {
|
||||||
|
return R.map(
|
||||||
|
R.compose(
|
||||||
|
R.when(R.pathEq(['key'], 'name'), accountNameColumnAccessor),
|
||||||
|
R.when(R.pathEq(['key'], 'total'), totalColumnAccessor),
|
||||||
|
R.when(
|
||||||
|
R.pathEq(['key'], 'percentage_of_column'),
|
||||||
|
percentageColumnAccessor,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)(columns);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -0,0 +1,8 @@
|
|||||||
|
import moment from 'moment';
|
||||||
|
|
||||||
|
export const getDefaultCustomersBalanceQuery = () => {
|
||||||
|
return {
|
||||||
|
asDate: moment().endOf('day').format('YYYY-MM-DD'),
|
||||||
|
filterByOption: 'with-transactions',
|
||||||
|
};
|
||||||
|
};
|
||||||
@@ -1,16 +1,14 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from 'react';
|
||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import 'style/pages/FinancialStatements/ContactsTransactions.scss';
|
|
||||||
|
|
||||||
import { FinancialStatement } from 'components';
|
import { FinancialStatement } from 'components';
|
||||||
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
import DashboardPageContent from 'components/Dashboard/DashboardPageContent';
|
||||||
|
|
||||||
import CustomersTransactionsHeader from './CustomersTransactionsHeader';
|
import CustomersTransactionsHeader from './CustomersTransactionsHeader';
|
||||||
import CustomersTransactionsTable from './CustomersTransactionsTable';
|
|
||||||
import CustomersTransactionsActionsBar from './CustomersTransactionsActionsBar';
|
import CustomersTransactionsActionsBar from './CustomersTransactionsActionsBar';
|
||||||
|
import { CustomersTransactionsBody } from './CustomersTransactionsBody';
|
||||||
|
|
||||||
import withCustomersTransactionsActions from './withCustomersTransactionsActions';
|
import withCustomersTransactionsActions from './withCustomersTransactionsActions';
|
||||||
import withCurrentOrganization from '../../../containers/Organization/withCurrentOrganization';
|
|
||||||
import { CustomersTransactionsLoadingBar } from './components';
|
import { CustomersTransactionsLoadingBar } from './components';
|
||||||
import { CustomersTransactionsProvider } from './CustomersTransactionsProvider';
|
import { CustomersTransactionsProvider } from './CustomersTransactionsProvider';
|
||||||
|
|
||||||
@@ -20,9 +18,6 @@ import { compose } from 'utils';
|
|||||||
* Customers transactions.
|
* Customers transactions.
|
||||||
*/
|
*/
|
||||||
function CustomersTransactions({
|
function CustomersTransactions({
|
||||||
// #withPreferences
|
|
||||||
organizationName,
|
|
||||||
|
|
||||||
//#withCustomersTransactionsActions
|
//#withCustomersTransactionsActions
|
||||||
toggleCustomersTransactionsFilterDrawer,
|
toggleCustomersTransactionsFilterDrawer,
|
||||||
}) {
|
}) {
|
||||||
@@ -66,24 +61,14 @@ function CustomersTransactions({
|
|||||||
<CustomersTransactionsLoadingBar />
|
<CustomersTransactionsLoadingBar />
|
||||||
<DashboardPageContent>
|
<DashboardPageContent>
|
||||||
<FinancialStatement>
|
<FinancialStatement>
|
||||||
<div className={'financial-statement--transactions'}>
|
<CustomersTransactionsHeader
|
||||||
<CustomersTransactionsHeader
|
pageFilter={filter}
|
||||||
pageFilter={filter}
|
onSubmitFilter={handleFilterSubmit}
|
||||||
onSubmitFilter={handleFilterSubmit}
|
/>
|
||||||
/>
|
<CustomersTransactionsBody />
|
||||||
|
|
||||||
<div class="financial-statement__body">
|
|
||||||
<CustomersTransactionsTable companyName={organizationName} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</FinancialStatement>
|
</FinancialStatement>
|
||||||
</DashboardPageContent>
|
</DashboardPageContent>
|
||||||
</CustomersTransactionsProvider>
|
</CustomersTransactionsProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default compose(
|
export default compose(withCustomersTransactionsActions)(CustomersTransactions);
|
||||||
withCurrentOrganization(({ organization }) => ({
|
|
||||||
organizationName: organization.name,
|
|
||||||
})),
|
|
||||||
withCustomersTransactionsActions,
|
|
||||||
)(CustomersTransactions);
|
|
||||||
|
|||||||
@@ -0,0 +1,36 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import * as R from 'ramda';
|
||||||
|
|
||||||
|
import withCurrentOrganization from 'containers/Organization/withCurrentOrganization';
|
||||||
|
|
||||||
|
import CustomersTransactionsTable from './CustomersTransactionsTable';
|
||||||
|
import { FinancialReportBody } from '../FinancialReportPage';
|
||||||
|
import { FinancialSheetSkeleton } from '../../../components/FinancialSheet';
|
||||||
|
|
||||||
|
import { useCustomersTransactionsContext } from './CustomersTransactionsProvider';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customers transactions body.
|
||||||
|
*/
|
||||||
|
function CustomersTransactionsBodyJSX({
|
||||||
|
// #withCurrentOrganization
|
||||||
|
organizationName,
|
||||||
|
}) {
|
||||||
|
const { isCustomersTransactionsLoading } = useCustomersTransactionsContext();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<FinancialReportBody>
|
||||||
|
{isCustomersTransactionsLoading ? (
|
||||||
|
<FinancialSheetSkeleton />
|
||||||
|
) : (
|
||||||
|
<CustomersTransactionsTable companyName={organizationName} />
|
||||||
|
)}
|
||||||
|
</FinancialReportBody>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CustomersTransactionsBody = R.compose(
|
||||||
|
withCurrentOrganization(({ organization }) => ({
|
||||||
|
organizationName: organization.name,
|
||||||
|
})),
|
||||||
|
)(CustomersTransactionsBodyJSX);
|
||||||
@@ -5,6 +5,7 @@ import intl from 'react-intl-universal';
|
|||||||
import moment from 'moment';
|
import moment from 'moment';
|
||||||
import * as Yup from 'yup';
|
import * as Yup from 'yup';
|
||||||
import { Formik, Form } from 'formik';
|
import { Formik, Form } from 'formik';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
import FinancialStatementHeader from 'containers/FinancialStatements/FinancialStatementHeader';
|
import FinancialStatementHeader from 'containers/FinancialStatements/FinancialStatementHeader';
|
||||||
import CustomersTransactionsHeaderGeneralPanel from './CustomersTransactionsHeaderGeneralPanel';
|
import CustomersTransactionsHeaderGeneralPanel from './CustomersTransactionsHeaderGeneralPanel';
|
||||||
@@ -67,7 +68,7 @@ function CustomersTransactionsHeader({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FinancialStatementHeader
|
<CustomerTransactionsDrawerHeader
|
||||||
isOpen={isFilterDrawerOpen}
|
isOpen={isFilterDrawerOpen}
|
||||||
drawerProps={{ onClose: handleDrawerClose }}
|
drawerProps={{ onClose: handleDrawerClose }}
|
||||||
>
|
>
|
||||||
@@ -95,7 +96,7 @@ function CustomersTransactionsHeader({
|
|||||||
</div>
|
</div>
|
||||||
</Form>
|
</Form>
|
||||||
</Formik>
|
</Formik>
|
||||||
</FinancialStatementHeader>
|
</CustomerTransactionsDrawerHeader>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -105,3 +106,9 @@ export default compose(
|
|||||||
})),
|
})),
|
||||||
withCustomersTransactionsActions,
|
withCustomersTransactionsActions,
|
||||||
)(CustomersTransactionsHeader);
|
)(CustomersTransactionsHeader);
|
||||||
|
|
||||||
|
const CustomerTransactionsDrawerHeader = styled(FinancialStatementHeader)`
|
||||||
|
.bp3-drawer {
|
||||||
|
max-height: 450px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import React, { useMemo } from 'react';
|
import React, { useMemo } from 'react';
|
||||||
import intl from 'react-intl-universal';
|
import intl from 'react-intl-universal';
|
||||||
|
import styled from 'styled-components';
|
||||||
|
|
||||||
|
import { DataTable, FinancialSheet } from 'components';
|
||||||
|
|
||||||
import FinancialSheet from 'components/FinancialSheet';
|
|
||||||
import DataTable from 'components/DataTable';
|
|
||||||
import { useCustomersTransactionsColumns } from './components';
|
import { useCustomersTransactionsColumns } from './components';
|
||||||
import { useCustomersTransactionsContext } from './CustomersTransactionsProvider';
|
import { useCustomersTransactionsContext } from './CustomersTransactionsProvider';
|
||||||
|
|
||||||
import { defaultExpanderReducer } from 'utils';
|
import { defaultExpanderReducer, tableRowTypesToClassnames } from 'utils';
|
||||||
|
import { TableStyle } from 'common';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Customers transactions table.
|
* Customers transactions table.
|
||||||
@@ -18,7 +20,6 @@ export default function CustomersTransactionsTable({
|
|||||||
// Customers transactions context.
|
// Customers transactions context.
|
||||||
const {
|
const {
|
||||||
customersTransactions: { tableRows },
|
customersTransactions: { tableRows },
|
||||||
isCustomersTransactionsLoading,
|
|
||||||
query,
|
query,
|
||||||
} = useCustomersTransactionsContext();
|
} = useCustomersTransactionsContext();
|
||||||
|
|
||||||
@@ -30,30 +31,79 @@ export default function CustomersTransactionsTable({
|
|||||||
[tableRows],
|
[tableRows],
|
||||||
);
|
);
|
||||||
|
|
||||||
const rowClassNames = (row) => {
|
|
||||||
return [`row-type--${row.original.row_types}`];
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FinancialSheet
|
<FinancialSheet
|
||||||
name="customer-transactions"
|
|
||||||
companyName={companyName}
|
companyName={companyName}
|
||||||
sheetType={intl.get('customers_transactions')}
|
sheetType={intl.get('customers_transactions')}
|
||||||
loading={isCustomersTransactionsLoading}
|
|
||||||
fromDate={query.from_date}
|
fromDate={query.from_date}
|
||||||
toDate={query.to_date}
|
toDate={query.to_date}
|
||||||
|
fullWidth={true}
|
||||||
>
|
>
|
||||||
<DataTable
|
<CustomersTransactionsDataTable
|
||||||
className="bigcapital-datatable--financial-report"
|
|
||||||
columns={columns}
|
columns={columns}
|
||||||
data={tableRows}
|
data={tableRows}
|
||||||
rowClassNames={rowClassNames}
|
rowClassNames={tableRowTypesToClassnames}
|
||||||
noInitialFetch={true}
|
noInitialFetch={true}
|
||||||
expandable={true}
|
expandable={true}
|
||||||
expanded={expandedRows}
|
expanded={expandedRows}
|
||||||
expandToggleColumn={1}
|
expandToggleColumn={1}
|
||||||
expandColumnSpace={0.8}
|
expandColumnSpace={0.8}
|
||||||
|
styleName={TableStyle.Constrant}
|
||||||
/>
|
/>
|
||||||
</FinancialSheet>
|
</FinancialSheet>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const CustomersTransactionsDataTable = styled(DataTable)`
|
||||||
|
.table {
|
||||||
|
.tbody {
|
||||||
|
.tr .td {
|
||||||
|
padding-top: 0.36rem;
|
||||||
|
padding-bottom: 0.36rem;
|
||||||
|
}
|
||||||
|
.tr:not(.no-results) .td:not(:first-of-type) {
|
||||||
|
border-left: 1px solid #ececec;
|
||||||
|
}
|
||||||
|
.tr:last-child .td {
|
||||||
|
border-bottom: 1px solid #e0e0e0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tr.row_type {
|
||||||
|
&--CUSTOMER {
|
||||||
|
.td {
|
||||||
|
&.customer_name {
|
||||||
|
font-weight: 500;
|
||||||
|
|
||||||
|
.cell-inner {
|
||||||
|
white-space: nowrap;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:not(:first-child).is-expanded .td {
|
||||||
|
border-top: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&--OPENING_BALANCE,
|
||||||
|
&--CLOSING_BALANCE {
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
&--CUSTOMER {
|
||||||
|
&.is-expanded {
|
||||||
|
.td.running_balance .cell-inner {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:not(:first-child).is-expanded .td {
|
||||||
|
border-top: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&--CUSTOMER:last-child {
|
||||||
|
.td {
|
||||||
|
border-bottom: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|||||||
@@ -3,12 +3,13 @@ import intl from 'react-intl-universal';
|
|||||||
import { If } from 'components';
|
import { If } from 'components';
|
||||||
import { useCustomersTransactionsContext } from './CustomersTransactionsProvider';
|
import { useCustomersTransactionsContext } from './CustomersTransactionsProvider';
|
||||||
import FinancialLoadingBar from '../FinancialLoadingBar';
|
import FinancialLoadingBar from '../FinancialLoadingBar';
|
||||||
import { getForceWidth, getColumnWidth } from 'utils';
|
import { getColumnWidth } from 'utils';
|
||||||
|
|
||||||
|
import { Align } from 'common';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve customers transactions columns.
|
* Retrieve customers transactions columns.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export const useCustomersTransactionsColumns = () => {
|
export const useCustomersTransactionsColumns = () => {
|
||||||
const {
|
const {
|
||||||
customersTransactions: { tableRows },
|
customersTransactions: { tableRows },
|
||||||
@@ -18,18 +19,8 @@ export const useCustomersTransactionsColumns = () => {
|
|||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
Header: intl.get('customer_name'),
|
Header: intl.get('customer_name'),
|
||||||
accessor: ({ cells }) => {
|
accessor: 'cells[0].value',
|
||||||
return (
|
|
||||||
<span
|
|
||||||
className={'force-width'}
|
|
||||||
style={{ minWidth: getForceWidth(cells[0].value) }}
|
|
||||||
>
|
|
||||||
{cells[0].value}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
},
|
|
||||||
className: 'customer_name',
|
className: 'customer_name',
|
||||||
// textOverview: true,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: intl.get('account_name'),
|
Header: intl.get('account_name'),
|
||||||
@@ -59,6 +50,7 @@ export const useCustomersTransactionsColumns = () => {
|
|||||||
minWidth: 100,
|
minWidth: 100,
|
||||||
magicSpacing: 10,
|
magicSpacing: 10,
|
||||||
}),
|
}),
|
||||||
|
align: Align.Right,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: intl.get('debit'),
|
Header: intl.get('debit'),
|
||||||
@@ -69,6 +61,7 @@ export const useCustomersTransactionsColumns = () => {
|
|||||||
minWidth: 100,
|
minWidth: 100,
|
||||||
magicSpacing: 10,
|
magicSpacing: 10,
|
||||||
}),
|
}),
|
||||||
|
align: Align.Right,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Header: intl.get('running_balance'),
|
Header: intl.get('running_balance'),
|
||||||
@@ -79,6 +72,7 @@ export const useCustomersTransactionsColumns = () => {
|
|||||||
minWidth: 120,
|
minWidth: 120,
|
||||||
magicSpacing: 10,
|
magicSpacing: 10,
|
||||||
}),
|
}),
|
||||||
|
align: Align.Right,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[tableRows],
|
[tableRows],
|
||||||
|
|||||||
@@ -1,18 +1,60 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { DashboardInsider } from 'components';
|
import { DashboardInsider } from 'components';
|
||||||
|
import styled from 'styled-components';
|
||||||
import { CLASSES } from 'common/classes';
|
import { CLASSES } from 'common/classes';
|
||||||
|
|
||||||
import 'style/pages/FinancialStatements/FinancialReportPage.scss';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Financial report page.
|
* Financial report page.
|
||||||
*/
|
*/
|
||||||
export default function FinancialReportPage(props) {
|
export default function FinancialReportPage(props) {
|
||||||
return (
|
return (
|
||||||
<DashboardInsider
|
<FinancialReportPageRoot
|
||||||
{...props}
|
{...props}
|
||||||
className={classNames(CLASSES.FINANCIAL_REPORT_INSIDER, props.className)}
|
className={classNames(CLASSES.FINANCIAL_REPORT_INSIDER, props.className)}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const FinancialComputeAlert = styled.div`
|
||||||
|
position: relative;
|
||||||
|
padding: 8px 20px;
|
||||||
|
border-radius: 2px;
|
||||||
|
background-color: #fdecda;
|
||||||
|
color: #342515;
|
||||||
|
font-size: 13px;
|
||||||
|
|
||||||
|
button {
|
||||||
|
font-size: 12px;
|
||||||
|
min-height: 16px;
|
||||||
|
padding: 0 4px;
|
||||||
|
|
||||||
|
&,
|
||||||
|
&:hover {
|
||||||
|
color: #824400;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
svg {
|
||||||
|
margin-right: 6px;
|
||||||
|
position: relative;
|
||||||
|
top: -2px;
|
||||||
|
fill: #975f19;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const FinancialProgressbar = styled.div`
|
||||||
|
.progress-materializecss {
|
||||||
|
top: -2px;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
export const FinancialReportPageRoot = styled(DashboardInsider)``;
|
||||||
|
|
||||||
|
export const FinancialReportBody = styled.div`
|
||||||
|
padding-left: 15px;
|
||||||
|
padding-right: 15px;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
`;
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user