mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-20 23:00:34 +00:00
feat: wip bank transaction matching
This commit is contained in:
@@ -1,30 +0,0 @@
|
|||||||
import { body } from 'express-validator';
|
|
||||||
import BaseController from '../BaseController';
|
|
||||||
import { Router } from 'express';
|
|
||||||
import { Service } from 'typedi';
|
|
||||||
|
|
||||||
@Service()
|
|
||||||
export class BankReconcileController extends BaseController {
|
|
||||||
/**
|
|
||||||
* Router constructor.
|
|
||||||
*/
|
|
||||||
public router() {
|
|
||||||
const router = Router();
|
|
||||||
|
|
||||||
router.post(
|
|
||||||
'/',
|
|
||||||
[
|
|
||||||
body('amount').exists(),
|
|
||||||
body('date').exists(),
|
|
||||||
body('fromAccountId').exists(),
|
|
||||||
body('toAccountId').exists(),
|
|
||||||
body('reference').optional({ nullable: true }),
|
|
||||||
],
|
|
||||||
this.validationResult,
|
|
||||||
this.createBankReconcileTransaction.bind(this)
|
|
||||||
);
|
|
||||||
return router;
|
|
||||||
}
|
|
||||||
|
|
||||||
createBankReconcileTransaction() {}
|
|
||||||
}
|
|
||||||
@@ -24,12 +24,14 @@ export class GetBankAccountSummary {
|
|||||||
.findById(bankAccountId)
|
.findById(bankAccountId)
|
||||||
.throwIfNotFound();
|
.throwIfNotFound();
|
||||||
|
|
||||||
|
// Retrieves the uncategorized transactions count of the given bank account.
|
||||||
const uncategorizedTranasctionsCount =
|
const uncategorizedTranasctionsCount =
|
||||||
await UncategorizedCashflowTransaction.query()
|
await UncategorizedCashflowTransaction.query()
|
||||||
.where('accountId', bankAccountId)
|
.where('accountId', bankAccountId)
|
||||||
.count('id as total')
|
.count('id as total')
|
||||||
.first();
|
.first();
|
||||||
|
|
||||||
|
// Retrieves the recognized transactions count of the given bank account.
|
||||||
const recognizedTransactionsCount = await RecognizedBankTransaction.query()
|
const recognizedTransactionsCount = await RecognizedBankTransaction.query()
|
||||||
.whereExists(
|
.whereExists(
|
||||||
UncategorizedCashflowTransaction.query().where(
|
UncategorizedCashflowTransaction.query().where(
|
||||||
|
|||||||
@@ -100,7 +100,6 @@ export class GetMatchedTransactions {
|
|||||||
moment(match.date).isSame(uncategorizedTransaction.date, 'day'),
|
moment(match.date).isSame(uncategorizedTransaction.date, 'day'),
|
||||||
closestResullts
|
closestResullts
|
||||||
);
|
);
|
||||||
|
|
||||||
const possibleMatches = R.difference(closestResullts, perfectMatches);
|
const possibleMatches = R.difference(closestResullts, perfectMatches);
|
||||||
|
|
||||||
return { perfectMatches, possibleMatches };
|
return { perfectMatches, possibleMatches };
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import {
|
|||||||
} from './types';
|
} from './types';
|
||||||
import { Inject, Service } from 'typedi';
|
import { Inject, Service } from 'typedi';
|
||||||
|
|
||||||
// @Service()
|
|
||||||
export abstract class GetMatchedTransactionsByType {
|
export abstract class GetMatchedTransactionsByType {
|
||||||
@Inject()
|
@Inject()
|
||||||
protected tenancy: HasTenancyService;
|
protected tenancy: HasTenancyService;
|
||||||
@@ -17,6 +16,7 @@ export abstract class GetMatchedTransactionsByType {
|
|||||||
* Retrieves the matched transactions.
|
* Retrieves the matched transactions.
|
||||||
* @param {number} tenantId -
|
* @param {number} tenantId -
|
||||||
* @param {GetMatchedTransactionsFilter} filter -
|
* @param {GetMatchedTransactionsFilter} filter -
|
||||||
|
* @returns {Promise<MatchedTransactionsPOJO>}
|
||||||
*/
|
*/
|
||||||
public async getMatchedTransactions(
|
public async getMatchedTransactions(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
@@ -31,6 +31,7 @@ export abstract class GetMatchedTransactionsByType {
|
|||||||
* Retrieves the matched transaction details.
|
* Retrieves the matched transaction details.
|
||||||
* @param {number} tenantId -
|
* @param {number} tenantId -
|
||||||
* @param {number} transactionId -
|
* @param {number} transactionId -
|
||||||
|
* @returns {Promise<MatchedTransactionPOJO>}
|
||||||
*/
|
*/
|
||||||
public async getMatchedTransaction(
|
public async getMatchedTransaction(
|
||||||
tenantId: number,
|
tenantId: number,
|
||||||
|
|||||||
@@ -1,25 +1,25 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { AppShellProvider, useAppShellContext } from './AppShellProvider';
|
import { AppShellProvider, useAppShellContext } from './AppContentShellProvider';
|
||||||
import { Box } from '../Layout';
|
import { Box, BoxProps } from '../../Layout';
|
||||||
import styles from './AppShell.module.scss';
|
import styles from './AppShell.module.scss';
|
||||||
|
|
||||||
interface AppShellProps {
|
interface AppContentShellProps {
|
||||||
topbarOffset?: number;
|
topbarOffset?: number;
|
||||||
mainProps: any;
|
mainProps?: BoxProps;
|
||||||
asideProps: any;
|
asideProps?: BoxProps;
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
hideAside?: boolean;
|
hideAside?: boolean;
|
||||||
hideMain?: boolean;
|
hideMain?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AppShell({
|
export function AppContentShell({
|
||||||
asideProps,
|
asideProps,
|
||||||
mainProps,
|
mainProps,
|
||||||
topbarOffset = 0,
|
topbarOffset = 0,
|
||||||
hideAside = false,
|
hideAside = false,
|
||||||
hideMain = false,
|
hideMain = false,
|
||||||
...restProps
|
...restProps
|
||||||
}: AppShellProps) {
|
}: AppContentShellProps) {
|
||||||
return (
|
return (
|
||||||
<AppShellProvider
|
<AppShellProvider
|
||||||
mainProps={mainProps}
|
mainProps={mainProps}
|
||||||
@@ -33,29 +33,29 @@ export function AppShell({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
AppShell.Main = AppShellMain;
|
interface AppContentShellMainProps extends BoxProps {}
|
||||||
AppShell.Aside = AppShellAside;
|
|
||||||
|
|
||||||
function AppShellMain({ ...props }) {
|
function AppContentShellMain({ ...props }: AppContentShellMainProps) {
|
||||||
const { hideMain } = useAppShellContext();
|
const { hideMain } = useAppShellContext();
|
||||||
|
|
||||||
if (hideMain === true) {
|
if (hideMain === true) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Box {...props} className={styles.main} />;
|
return <Box {...props} className={styles.main} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AppShellAsideProps {
|
interface AppContentShellAsideProps extends BoxProps {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
function AppShellAside({ ...props }: AppShellAsideProps) {
|
function AppContentShellAside({ ...props }: AppContentShellAsideProps) {
|
||||||
const { hideAside } = useAppShellContext();
|
const { hideAside } = useAppShellContext();
|
||||||
|
|
||||||
console.log(hideAside, 'hideAsidehideAsidehideAsidehideAside');
|
|
||||||
if (hideAside === true) {
|
if (hideAside === true) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return <Box {...props} className={styles.aside} />;
|
return <Box {...props} className={styles.aside} />;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
AppContentShell.Main = AppContentShellMain;
|
||||||
|
AppContentShell.Aside = AppContentShellAside;
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
export * from './AppContentShell';
|
||||||
1
packages/webapp/src/components/AppShell/index.ts
Normal file
1
packages/webapp/src/components/AppShell/index.ts
Normal file
@@ -0,0 +1 @@
|
|||||||
|
export * from './AppContentShell';
|
||||||
@@ -3,7 +3,6 @@ import { Button, Classes, NavbarGroup } from '@blueprintjs/core';
|
|||||||
import * as R from 'ramda';
|
import * as R from 'ramda';
|
||||||
import { Can, DashboardActionsBar, Icon } from '@/components';
|
import { Can, DashboardActionsBar, Icon } from '@/components';
|
||||||
import { AbilitySubject, BankRuleAction } from '@/constants/abilityOption';
|
import { AbilitySubject, BankRuleAction } from '@/constants/abilityOption';
|
||||||
import withAlertActions from '@/containers/Alert/withAlertActions';
|
|
||||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||||
import { DialogsName } from '@/constants/dialogs';
|
import { DialogsName } from '@/constants/dialogs';
|
||||||
|
|
||||||
@@ -31,7 +30,6 @@ function RulesListActionsBarRoot({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const RulesListActionsBar = R.compose(
|
export const RulesListActionsBar = R.compose(withDialogActions)(
|
||||||
withDialogActions,
|
RulesListActionsBarRoot,
|
||||||
withAlertActions,
|
);
|
||||||
)(RulesListActionsBarRoot);
|
|
||||||
|
|||||||
@@ -8,9 +8,7 @@ import {
|
|||||||
} from '@/components';
|
} from '@/components';
|
||||||
|
|
||||||
import withAlertsActions from '@/containers/Alert/withAlertActions';
|
import withAlertsActions from '@/containers/Alert/withAlertActions';
|
||||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
|
||||||
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
import withDialogActions from '@/containers/Dialog/withDialogActions';
|
||||||
import withDashboardActions from '@/containers/Dashboard/withDashboardActions';
|
|
||||||
|
|
||||||
import { useBankRulesTableColumns } from './hooks';
|
import { useBankRulesTableColumns } from './hooks';
|
||||||
import { BankRulesTableActionsMenu } from './_components';
|
import { BankRulesTableActionsMenu } from './_components';
|
||||||
@@ -25,9 +23,6 @@ function RulesTable({
|
|||||||
// #withAlertsActions
|
// #withAlertsActions
|
||||||
openAlert,
|
openAlert,
|
||||||
|
|
||||||
// #withDrawerActions
|
|
||||||
openDrawer,
|
|
||||||
|
|
||||||
// #withDialogAction
|
// #withDialogAction
|
||||||
openDialog,
|
openDialog,
|
||||||
}) {
|
}) {
|
||||||
@@ -81,8 +76,6 @@ function RulesTable({
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const BankRulesTable = R.compose(
|
export const BankRulesTable = R.compose(
|
||||||
withDashboardActions,
|
|
||||||
withAlertsActions,
|
withAlertsActions,
|
||||||
withDrawerActions,
|
|
||||||
withDialogActions,
|
withDialogActions,
|
||||||
)(RulesTable);
|
)(RulesTable);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ import {
|
|||||||
import { AccountTransactionsDetailsBar } from './AccountTransactionsDetailsBar';
|
import { AccountTransactionsDetailsBar } from './AccountTransactionsDetailsBar';
|
||||||
import { AccountTransactionsProgressBar } from './components';
|
import { AccountTransactionsProgressBar } from './components';
|
||||||
import { AccountTransactionsFilterTabs } from './AccountTransactionsFilterTabs';
|
import { AccountTransactionsFilterTabs } from './AccountTransactionsFilterTabs';
|
||||||
import { AppShell } from '@/components/AppShell/AppShell';
|
import { AppContentShell } from '@/components/AppShell';
|
||||||
import { CategorizeTransactionAside } from '../CategorizeTransactionAside/CategorizeTransactionAside';
|
import { CategorizeTransactionAside } from '../CategorizeTransactionAside/CategorizeTransactionAside';
|
||||||
import { withBanking } from '../withBanking';
|
import { withBanking } from '../withBanking';
|
||||||
|
|
||||||
@@ -28,8 +28,8 @@ function AccountTransactionsListRoot({
|
|||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<AccountTransactionsProvider>
|
<AccountTransactionsProvider>
|
||||||
<AppShell hideAside={!openMatchingTransactionAside}>
|
<AppContentShell hideAside={!openMatchingTransactionAside}>
|
||||||
<AppShell.Main>
|
<AppContentShell.Main>
|
||||||
<AccountTransactionsActionsBar />
|
<AccountTransactionsActionsBar />
|
||||||
<AccountTransactionsDetailsBar />
|
<AccountTransactionsDetailsBar />
|
||||||
<AccountTransactionsProgressBar />
|
<AccountTransactionsProgressBar />
|
||||||
@@ -41,12 +41,12 @@ function AccountTransactionsListRoot({
|
|||||||
<AccountTransactionsContent />
|
<AccountTransactionsContent />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
</DashboardPageContent>
|
</DashboardPageContent>
|
||||||
</AppShell.Main>
|
</AppContentShell.Main>
|
||||||
|
|
||||||
<AppShell.Aside>
|
<AppContentShell.Aside>
|
||||||
<CategorizeTransactionAside />
|
<CategorizeTransactionAside />
|
||||||
</AppShell.Aside>
|
</AppContentShell.Aside>
|
||||||
</AppShell>
|
</AppContentShell>
|
||||||
</AccountTransactionsProvider>
|
</AccountTransactionsProvider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// @ts-nocheck
|
// @ts-nocheck
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import styled from 'styled-components';
|
import styled from 'styled-components';
|
||||||
|
import { Intent } from '@blueprintjs/core';
|
||||||
import {
|
import {
|
||||||
DataTable,
|
DataTable,
|
||||||
TableFastCell,
|
TableFastCell,
|
||||||
@@ -14,7 +14,6 @@ import {
|
|||||||
import { TABLES } from '@/constants/tables';
|
import { TABLES } from '@/constants/tables';
|
||||||
|
|
||||||
import withSettings from '@/containers/Settings/withSettings';
|
import withSettings from '@/containers/Settings/withSettings';
|
||||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
|
||||||
import { withBankingActions } from '../withBankingActions';
|
import { withBankingActions } from '../withBankingActions';
|
||||||
|
|
||||||
import { useMemorizedColumnsWidths } from '@/hooks';
|
import { useMemorizedColumnsWidths } from '@/hooks';
|
||||||
@@ -26,7 +25,6 @@ import { useAccountUncategorizedTransactionsContext } from './AllTransactionsUnc
|
|||||||
|
|
||||||
import { compose } from '@/utils';
|
import { compose } from '@/utils';
|
||||||
import { useExcludeUncategorizedTransaction } from '@/hooks/query/bank-rules';
|
import { useExcludeUncategorizedTransaction } from '@/hooks/query/bank-rules';
|
||||||
import { Intent } from '@blueprintjs/core';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Account transactions data table.
|
* Account transactions data table.
|
||||||
@@ -37,9 +35,6 @@ function AccountTransactionsDataTable({
|
|||||||
|
|
||||||
// #withBankingActions
|
// #withBankingActions
|
||||||
setUncategorizedTransactionIdForMatching,
|
setUncategorizedTransactionIdForMatching,
|
||||||
|
|
||||||
// #withDrawerActions
|
|
||||||
openDrawer,
|
|
||||||
}) {
|
}) {
|
||||||
// Retrieve table columns.
|
// Retrieve table columns.
|
||||||
const columns = useAccountUncategorizedTransactionsColumns();
|
const columns = useAccountUncategorizedTransactionsColumns();
|
||||||
@@ -102,7 +97,9 @@ function AccountTransactionsDataTable({
|
|||||||
vListOverscanRowCount={0}
|
vListOverscanRowCount={0}
|
||||||
initialColumnsWidths={initialColumnsWidths}
|
initialColumnsWidths={initialColumnsWidths}
|
||||||
onColumnResizing={handleColumnResizing}
|
onColumnResizing={handleColumnResizing}
|
||||||
noResults={'There is no uncategorized transactions in the current account.'}
|
noResults={
|
||||||
|
'There is no uncategorized transactions in the current account.'
|
||||||
|
}
|
||||||
className="table-constrant"
|
className="table-constrant"
|
||||||
payload={{
|
payload={{
|
||||||
onExclude: handleExcludeTransaction,
|
onExclude: handleExcludeTransaction,
|
||||||
@@ -116,7 +113,6 @@ export default compose(
|
|||||||
withSettings(({ cashflowTransactionsSettings }) => ({
|
withSettings(({ cashflowTransactionsSettings }) => ({
|
||||||
cashflowTansactionsTableSize: cashflowTransactionsSettings?.tableSize,
|
cashflowTansactionsTableSize: cashflowTransactionsSettings?.tableSize,
|
||||||
})),
|
})),
|
||||||
withDrawerActions,
|
|
||||||
withBankingActions,
|
withBankingActions,
|
||||||
)(AccountTransactionsDataTable);
|
)(AccountTransactionsDataTable);
|
||||||
|
|
||||||
|
|||||||
@@ -1,37 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
interface UncategorizedTransactionsFilterValue {}
|
|
||||||
|
|
||||||
const UncategorizedTransactionsFilterContext =
|
|
||||||
React.createContext<UncategorizedTransactionsFilterValue>(
|
|
||||||
{} as UncategorizedTransactionsFilterValue,
|
|
||||||
);
|
|
||||||
|
|
||||||
interface UncategorizedTransactionsFilterProviderProps {
|
|
||||||
children: React.ReactNode;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
function UncategorizedTransactionsFilterProvider({
|
|
||||||
...props
|
|
||||||
}: UncategorizedTransactionsFilterProviderProps) {
|
|
||||||
// Provider payload.
|
|
||||||
const provider = {};
|
|
||||||
|
|
||||||
return (
|
|
||||||
<UncategorizedTransactionsFilterContext.Provider
|
|
||||||
value={provider}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const useUncategorizedTransactionsFilter = () =>
|
|
||||||
React.useContext(UncategorizedTransactionsFilterContext);
|
|
||||||
|
|
||||||
export {
|
|
||||||
UncategorizedTransactionsFilterProvider,
|
|
||||||
useUncategorizedTransactionsFilter,
|
|
||||||
};
|
|
||||||
@@ -6,7 +6,6 @@ import * as R from 'ramda';
|
|||||||
import '@/style/pages/CashFlow/AccountTransactions/List.scss';
|
import '@/style/pages/CashFlow/AccountTransactions/List.scss';
|
||||||
|
|
||||||
import { AccountTransactionsUncategorizeFilter } from './AccountTransactionsUncategorizeFilter';
|
import { AccountTransactionsUncategorizeFilter } from './AccountTransactionsUncategorizeFilter';
|
||||||
import { UncategorizedTransactionsFilterProvider } from './AccountUncategorizedTransactionsFilterProvider';
|
|
||||||
import {
|
import {
|
||||||
WithBankingActionsProps,
|
WithBankingActionsProps,
|
||||||
withBankingActions,
|
withBankingActions,
|
||||||
@@ -23,6 +22,7 @@ function AllTransactionsUncategorizedRoot({
|
|||||||
// #withBankingActions
|
// #withBankingActions
|
||||||
closeMatchingTransactionAside,
|
closeMatchingTransactionAside,
|
||||||
}: AllTransactionsUncategorizedProps) {
|
}: AllTransactionsUncategorizedProps) {
|
||||||
|
// Close the match aside once leaving the page.
|
||||||
useEffect(
|
useEffect(
|
||||||
() => () => {
|
() => () => {
|
||||||
closeMatchingTransactionAside();
|
closeMatchingTransactionAside();
|
||||||
@@ -31,12 +31,10 @@ function AllTransactionsUncategorizedRoot({
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<UncategorizedTransactionsFilterProvider>
|
<Box>
|
||||||
<Box>
|
<AccountTransactionsUncategorizeFilter />
|
||||||
<AccountTransactionsUncategorizeFilter />
|
<AccountTransactionsSwitcher />
|
||||||
<AccountTransactionsSwitcher />
|
</Box>
|
||||||
</Box>
|
|
||||||
</UncategorizedTransactionsFilterProvider>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import {
|
|||||||
} from '@/components';
|
} from '@/components';
|
||||||
import { TABLES } from '@/constants/tables';
|
import { TABLES } from '@/constants/tables';
|
||||||
|
|
||||||
import withSettings from '@/containers/Settings/withSettings';
|
|
||||||
import withAlertsActions from '@/containers/Alert/withAlertActions';
|
import withAlertsActions from '@/containers/Alert/withAlertActions';
|
||||||
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
import withDrawerActions from '@/containers/Drawer/withDrawerActions';
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user