Merge pull request #564 from bigcapitalhq/fix-banking-bugs

fix: Banking service bugs
This commit is contained in:
Ahmed Bouhuolia
2024-08-05 23:06:03 +02:00
committed by GitHub
20 changed files with 276 additions and 128 deletions

View File

@@ -20,6 +20,7 @@ export default class UncategorizedCashflowTransaction extends mixin(
description!: string;
plaidTransactionId!: string;
recognizedTransactionId!: number;
excludedAt: Date;
/**
* Table name.
@@ -45,6 +46,7 @@ export default class UncategorizedCashflowTransaction extends mixin(
'isDepositTransaction',
'isWithdrawalTransaction',
'isRecognized',
'isExcluded'
];
}
@@ -89,6 +91,14 @@ export default class UncategorizedCashflowTransaction extends mixin(
return !!this.recognizedTransactionId;
}
/**
* Detarmines whether the transaction is excluded.
* @returns {boolean}
*/
public get isExcluded(): boolean {
return !!this.excludedAt;
}
/**
* Model modifiers.
*/

View File

@@ -1,6 +1,7 @@
import { Inject, Service } from 'typedi';
import { initialize } from 'objection';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import { UncategorizedTransactionTransformer } from '@/services/Cashflow/UncategorizedTransactionTransformer';
@Service()
export class GetBankAccountSummary {
@@ -31,17 +32,21 @@ export class GetBankAccountSummary {
.findById(bankAccountId)
.throwIfNotFound();
const commonQuery = (q) => {
// Include just the given account.
q.where('accountId', bankAccountId);
// Only the not excluded.
q.modify('notExcluded');
// Only the not categorized.
q.modify('notCategorized');
};
// Retrieves the uncategorized transactions count of the given bank account.
const uncategorizedTranasctionsCount =
await UncategorizedCashflowTransaction.query().onBuild((q) => {
// Include just the given account.
q.where('accountId', bankAccountId);
// Only the not excluded.
q.modify('notExcluded');
// Only the not categorized.
q.modify('notCategorized');
commonQuery(q);
// Only the not matched bank transactions.
q.withGraphJoined('matchedBankTransactions');
@@ -52,25 +57,40 @@ export class GetBankAccountSummary {
q.first();
});
// Retrieves the recognized transactions count of the given bank account.
const recognizedTransactionsCount = await RecognizedBankTransaction.query()
.whereExists(
UncategorizedCashflowTransaction.query().where(
'accountId',
bankAccountId
)
)
.count('id as total')
.first();
// Retrives the recognized transactions count.
const recognizedTransactionsCount =
await UncategorizedCashflowTransaction.query().onBuild((q) => {
commonQuery(q);
q.withGraphJoined('recognizedTransaction');
q.whereNotNull('recognizedTransaction.id');
// Count the results.
q.count('uncategorized_cashflow_transactions.id as total');
q.first();
});
const excludedTransactionsCount =
await UncategorizedCashflowTransaction.query().onBuild((q) => {
q.where('accountId', bankAccountId);
q.modify('excluded');
// Count the results.
q.count('uncategorized_cashflow_transactions.id as total');
q.first();
});
const totalUncategorizedTransactions =
uncategorizedTranasctionsCount?.total || 0;
const totalRecognizedTransactions = recognizedTransactionsCount?.total || 0;
const totalExcludedTransactions = excludedTransactionsCount?.total || 0;
return {
name: bankAccount.name,
totalUncategorizedTransactions,
totalRecognizedTransactions,
totalExcludedTransactions,
};
}
}

View File

@@ -1,7 +1,11 @@
import { Knex } from 'knex';
import { Inject, Service } from 'typedi';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import UnitOfWork from '@/services/UnitOfWork';
import { Inject, Service } from 'typedi';
import { validateTransactionNotCategorized } from './utils';
import {
validateTransactionNotCategorized,
validateTransactionNotExcluded,
} from './utils';
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
import events from '@/subscribers/events';
import {
@@ -37,9 +41,13 @@ export class ExcludeBankTransaction {
.findById(uncategorizedTransactionId)
.throwIfNotFound();
// Validate the transaction shouldn't be excluded.
validateTransactionNotExcluded(oldUncategorizedTransaction);
// Validate the transaction shouldn't be categorized.
validateTransactionNotCategorized(oldUncategorizedTransaction);
return this.uow.withTransaction(tenantId, async (trx) => {
return this.uow.withTransaction(tenantId, async (trx: Knex.Transaction) => {
await this.eventPublisher.emitAsync(events.bankTransactions.onExcluding, {
tenantId,
uncategorizedTransactionId,

View File

@@ -1,6 +1,6 @@
import { Inject, Service } from 'typedi';
import PromisePool from '@supercharge/promise-pool';
import { castArray } from 'lodash';
import { castArray, uniq } from 'lodash';
import { ExcludeBankTransaction } from './ExcludeBankTransaction';
@Service()
@@ -18,7 +18,7 @@ export class ExcludeBankTransactions {
tenantId: number,
bankTransactionIds: Array<number> | number
) {
const _bankTransactionIds = castArray(bankTransactionIds);
const _bankTransactionIds = uniq(castArray(bankTransactionIds));
await PromisePool.withConcurrency(1)
.for(_bankTransactionIds)

View File

@@ -1,7 +1,11 @@
import { Knex } from 'knex';
import { Inject, Service } from 'typedi';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import UnitOfWork from '@/services/UnitOfWork';
import { Inject, Service } from 'typedi';
import { validateTransactionNotCategorized } from './utils';
import {
validateTransactionNotCategorized,
validateTransactionShouldBeExcluded,
} from './utils';
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
import events from '@/subscribers/events';
import {
@@ -37,9 +41,13 @@ export class UnexcludeBankTransaction {
.findById(uncategorizedTransactionId)
.throwIfNotFound();
// Validate the transaction should be excludded.
validateTransactionShouldBeExcluded(oldUncategorizedTransaction);
// Validate the transaction shouldn't be categorized.
validateTransactionNotCategorized(oldUncategorizedTransaction);
return this.uow.withTransaction(tenantId, async (trx) => {
return this.uow.withTransaction(tenantId, async (trx: Knex.Transaction) => {
await this.eventPublisher.emitAsync(
events.bankTransactions.onUnexcluding,
{

View File

@@ -1,7 +1,7 @@
import { Inject, Service } from 'typedi';
import PromisePool from '@supercharge/promise-pool';
import { UnexcludeBankTransaction } from './UnexcludeBankTransaction';
import { castArray } from 'lodash';
import { castArray, uniq } from 'lodash';
@Service()
export class UnexcludeBankTransactions {
@@ -17,7 +17,7 @@ export class UnexcludeBankTransactions {
tenantId: number,
bankTransactionIds: Array<number> | number
) {
const _bankTransactionIds = castArray(bankTransactionIds);
const _bankTransactionIds = uniq(castArray(bankTransactionIds));
await PromisePool.withConcurrency(1)
.for(_bankTransactionIds)

View File

@@ -3,6 +3,8 @@ import UncategorizedCashflowTransaction from '@/models/UncategorizedCashflowTran
const ERRORS = {
TRANSACTION_ALREADY_CATEGORIZED: 'TRANSACTION_ALREADY_CATEGORIZED',
TRANSACTION_ALREADY_EXCLUDED: 'TRANSACTION_ALREADY_EXCLUDED',
TRANSACTION_NOT_EXCLUDED: 'TRANSACTION_NOT_EXCLUDED',
};
export const validateTransactionNotCategorized = (
@@ -12,3 +14,19 @@ export const validateTransactionNotCategorized = (
throw new ServiceError(ERRORS.TRANSACTION_ALREADY_CATEGORIZED);
}
};
export const validateTransactionNotExcluded = (
transaction: UncategorizedCashflowTransaction
) => {
if (transaction.isExcluded) {
throw new ServiceError(ERRORS.TRANSACTION_ALREADY_EXCLUDED);
}
};
export const validateTransactionShouldBeExcluded = (
transaction: UncategorizedCashflowTransaction
) => {
if (!transaction.isExcluded) {
throw new ServiceError(ERRORS.TRANSACTION_NOT_EXCLUDED);
}
};

View File

@@ -34,6 +34,7 @@ export class GetRecognizedTransactionsService {
q.withGraphFetched('recognizedTransaction.assignAccount');
q.withGraphFetched('recognizedTransaction.bankRule');
q.whereNotNull('recognizedTransactionId');
q.modify('notExcluded');
if (_filter.accountId) {
q.where('accountId', _filter.accountId);

View File

@@ -1,5 +1,9 @@
import React from 'react';
import { AppShellProvider, useAppShellContext } from './AppContentShellProvider';
// @ts-nocheck
import React, { forwardRef, Ref } from 'react';
import {
AppShellProvider,
useAppShellContext,
} from './AppContentShellProvider';
import { Box, BoxProps } from '../../Layout';
import styles from './AppContentShell.module.scss';
@@ -12,50 +16,73 @@ interface AppContentShellProps {
hideMain?: boolean;
}
export function AppContentShell({
asideProps,
mainProps,
topbarOffset = 0,
hideAside = false,
hideMain = false,
...restProps
}: AppContentShellProps) {
return (
<AppShellProvider
mainProps={mainProps}
asideProps={asideProps}
topbarOffset={topbarOffset}
hideAside={hideAside}
hideMain={hideMain}
>
<Box {...restProps} className={styles.root} />
</AppShellProvider>
);
}
export const AppContentShell = forwardRef(
(
{
asideProps,
mainProps,
topbarOffset = 0,
hideAside = false,
hideMain = false,
...restProps
}: AppContentShellProps,
ref: Ref<HTMLDivElement>,
) => {
return (
<AppShellProvider
mainProps={mainProps}
asideProps={asideProps}
topbarOffset={topbarOffset}
hideAside={hideAside}
hideMain={hideMain}
>
<Box {...restProps} className={styles.root} ref={ref} />
</AppShellProvider>
);
},
);
AppContentShell.displayName = 'AppContentShell';
interface AppContentShellMainProps extends BoxProps {}
function AppContentShellMain({ ...props }: AppContentShellMainProps) {
const { hideMain } = useAppShellContext();
/**
* Main content of the app shell.
* @param {AppContentShellMainProps} props -
* @returns {React.ReactNode}
*/
const AppContentShellMain = forwardRef(
({ ...props }: AppContentShellMainProps, ref: Ref<HTMLDivElement>) => {
const { hideMain } = useAppShellContext();
if (hideMain === true) {
return null;
}
return <Box {...props} className={styles.main} />;
}
if (hideMain === true) {
return null;
}
return <Box {...props} className={styles.main} ref={ref} />;
},
);
AppContentShellMain.displayName = 'AppContentShellMain';
interface AppContentShellAsideProps extends BoxProps {
children: React.ReactNode;
}
function AppContentShellAside({ ...props }: AppContentShellAsideProps) {
const { hideAside } = useAppShellContext();
/**
* Aside content of the app shell.
* @param {AppContentShellAsideProps} props
* @returns {React.ReactNode}
*/
const AppContentShellAside = forwardRef(
({ ...props }: AppContentShellAsideProps, ref: Ref<HTMLDivElement>) => {
const { hideAside } = useAppShellContext();
if (hideAside === true) {
return null;
}
return <Box {...props} className={styles.aside} />;
}
if (hideAside === true) {
return null;
}
return <Box {...props} className={styles.aside} ref={ref} />;
},
);
AppContentShellAside.displayName = 'AppContentShellAside';
AppContentShell.Main = AppContentShellMain;
AppContentShell.Aside = AppContentShellAside;

View File

@@ -25,14 +25,13 @@ function TableVirtualizedListRow({ index, isScrolling, isVisible, style }) {
export function TableVirtualizedListRows() {
const {
table: { page },
props: { vListrowHeight, vListOverscanRowCount },
props: { vListrowHeight, vListOverscanRowCount, windowScrollerProps },
} = useContext(TableContext);
// Dashboard content pane.
const dashboardContentPane = React.useMemo(
() => document.querySelector(`.${CLASSES.DASHBOARD_CONTENT_PANE}`),
[],
);
const scrollElement =
windowScrollerProps?.scrollElement ||
document.querySelector(`.${CLASSES.DASHBOARD_CONTENT_PANE}`);
const rowRenderer = React.useCallback(
({ key, ...args }) => <TableVirtualizedListRow {...args} key={key} />,
@@ -40,7 +39,7 @@ export function TableVirtualizedListRows() {
);
return (
<WindowScroller scrollElement={dashboardContentPane}>
<WindowScroller scrollElement={scrollElement}>
{({ height, isScrolling, onChildScroll, scrollTop }) => (
<AutoSizer disableHeight>
{({ width }) => (

View File

@@ -1,12 +1,15 @@
import React from 'react';
import React, { forwardRef, Ref } from 'react';
import { HTMLDivProps, Props } from '@blueprintjs/core';
export interface BoxProps extends Props, HTMLDivProps {
className?: string;
}
export function Box({ className, ...rest }: BoxProps) {
const Element = 'div';
export const Box = forwardRef(
({ className, ...rest }: BoxProps, ref: Ref<HTMLDivElement>) => {
const Element = 'div';
return <Element className={className} {...rest} />;
}
return <Element className={className} ref={ref} {...rest} />;
},
);
Box.displayName = '@bigcapital/Box';

View File

@@ -0,0 +1,10 @@
export const BANK_QUERY_KEY = {
BANK_RULES: 'BANK_RULE',
BANK_TRANSACTION_MATCHES: 'BANK_TRANSACTION_MATCHES',
RECOGNIZED_BANK_TRANSACTION: 'RECOGNIZED_BANK_TRANSACTION',
EXCLUDED_BANK_TRANSACTIONS_INFINITY: 'EXCLUDED_BANK_TRANSACTIONS_INFINITY',
RECOGNIZED_BANK_TRANSACTIONS_INFINITY:
'RECOGNIZED_BANK_TRANSACTIONS_INFINITY',
BANK_ACCOUNT_SUMMARY_META: 'BANK_ACCOUNT_SUMMARY_META',
AUTOFILL_CATEGORIZE_BANK_TRANSACTION: 'AUTOFILL_CATEGORIZE_BANK_TRANSACTION',
};

View File

@@ -1,4 +1,5 @@
// @ts-nocheck
import { useMemo } from 'react';
import styled from 'styled-components';
import { ContentTabs } from '@/components/ContentTabs/ContentTabs';
import { useAccountTransactionsContext } from './AccountTransactionsProvider';
@@ -8,15 +9,19 @@ const AccountContentTabs = styled(ContentTabs)`
`;
export function AccountTransactionsFilterTabs() {
const { filterTab, setFilterTab, currentAccount } =
const { filterTab, setFilterTab, bankAccountMetaSummary, currentAccount } =
useAccountTransactionsContext();
const handleChange = (value) => {
setFilterTab(value);
};
const hasUncategorizedTransx = Boolean(
currentAccount.uncategorized_transactions,
// Detarmines whether show the uncategorized transactions tab.
const hasUncategorizedTransx = useMemo(
() =>
bankAccountMetaSummary?.totalUncategorizedTransactions > 0 ||
bankAccountMetaSummary?.totalExcludedTransactions > 0,
[bankAccountMetaSummary],
);
return (

View File

@@ -29,28 +29,41 @@ function AccountTransactionsListRoot({
return (
<AccountTransactionsProvider>
<AppContentShell hideAside={!openMatchingTransactionAside}>
<AppContentShell.Main>
<AccountTransactionsActionsBar />
<AccountTransactionsDetailsBar />
<AccountTransactionsProgressBar />
<DashboardPageContent>
<AccountTransactionsFilterTabs />
<Suspense fallback={<Spinner size={30} />}>
<AccountTransactionsContent />
</Suspense>
</DashboardPageContent>
</AppContentShell.Main>
<AppContentShell.Aside>
<CategorizeTransactionAside />
</AppContentShell.Aside>
<AccountTransactionsMain />
<AccountTransactionsAside />
</AppContentShell>
</AccountTransactionsProvider>
);
}
function AccountTransactionsMain() {
const { setScrollableRef } = useAccountTransactionsContext();
return (
<AppContentShell.Main ref={(e) => setScrollableRef(e)}>
<AccountTransactionsActionsBar />
<AccountTransactionsDetailsBar />
<AccountTransactionsProgressBar />
<DashboardPageContent>
<AccountTransactionsFilterTabs />
<Suspense fallback={<Spinner size={30} />}>
<AccountTransactionsContent />
</Suspense>
</DashboardPageContent>
</AppContentShell.Main>
);
}
function AccountTransactionsAside() {
return (
<AppContentShell.Aside>
<CategorizeTransactionAside />
</AppContentShell.Aside>
);
}
export default R.compose(
withBanking(
({ selectedUncategorizedTransactionId, openMatchingTransactionAside }) => ({

View File

@@ -1,5 +1,5 @@
// @ts-nocheck
import React from 'react';
import React, { useRef, useState } from 'react';
import { useParams } from 'react-router-dom';
import { DashboardInsider } from '@/components';
import { useCashflowAccounts, useAccount } from '@/hooks/query';
@@ -41,6 +41,8 @@ function AccountTransactionsProvider({ query, ...props }) {
isLoading: isBankAccountMetaSummaryLoading,
} = useGetBankAccountSummaryMeta(accountId);
const [scrollableRef, setScrollableRef] = useState();
// Provider payload.
const provider = {
accountId,
@@ -56,6 +58,9 @@ function AccountTransactionsProvider({ query, ...props }) {
filterTab,
setFilterTab,
scrollableRef,
setScrollableRef
};
return (

View File

@@ -16,6 +16,7 @@ import { TABLES } from '@/constants/tables';
import { useMemorizedColumnsWidths } from '@/hooks';
import { useExcludedTransactionsColumns } from './_utils';
import { useExcludedTransactionsBoot } from './ExcludedTransactionsTableBoot';
import { useAccountTransactionsContext } from '../AccountTransactionsProvider';
import { ActionsMenu } from './_components';
import { useUnexcludeUncategorizedTransaction } from '@/hooks/query/bank-rules';
@@ -37,6 +38,8 @@ function ExcludedTransactionsTableRoot({
const { mutateAsync: unexcludeBankTransaction } =
useUnexcludeUncategorizedTransaction();
const { scrollableRef } = useAccountTransactionsContext();
// Retrieve table columns.
const columns = useExcludedTransactionsColumns();
@@ -97,6 +100,7 @@ function ExcludedTransactionsTableRoot({
className="table-constrant"
selectionColumn={true}
onSelectedRowsChange={handleSelectedRowsChange}
windowScrollerProps={{ scrollElement: scrollableRef }}
payload={{
onRestore: handleRestoreClick,
}}

View File

@@ -20,6 +20,7 @@ import { useRecognizedTransactionsBoot } from './RecognizedTransactionsTableBoot
import { ActionsMenu } from './_components';
import { compose } from '@/utils';
import { useAccountTransactionsContext } from '../AccountTransactionsProvider';
import { useExcludeUncategorizedTransaction } from '@/hooks/query/bank-rules';
import {
WithBankingActionsProps,
@@ -33,8 +34,8 @@ interface RecognizedTransactionsTableProps extends WithBankingActionsProps {}
* Renders the recognized account transactions datatable.
*/
function RecognizedTransactionsTableRoot({
// #withBanking
setUncategorizedTransactionIdForMatching,
// #withBankingActions
setTransactionsToCategorizeSelected,
}: RecognizedTransactionsTableProps) {
const { mutateAsync: excludeBankTransaction } =
useExcludeUncategorizedTransaction();
@@ -49,9 +50,11 @@ function RecognizedTransactionsTableRoot({
const [initialColumnsWidths, , handleColumnResizing] =
useMemorizedColumnsWidths(TABLES.UNCATEGORIZED_ACCOUNT_TRANSACTIONS);
const { scrollableRef } = useAccountTransactionsContext();
// Handle cell click.
const handleCellClick = (cell, event) => {
setUncategorizedTransactionIdForMatching(
setTransactionsToCategorizeSelected(
cell.row.original.uncategorized_transaction_id,
);
};
@@ -74,7 +77,7 @@ function RecognizedTransactionsTableRoot({
// Handles categorize button click.
const handleCategorizeClick = (transaction) => {
setUncategorizedTransactionIdForMatching(
setTransactionsToCategorizeSelected(
transaction.uncategorized_transaction_id,
);
};
@@ -102,6 +105,7 @@ function RecognizedTransactionsTableRoot({
vListOverscanRowCount={0}
initialColumnsWidths={initialColumnsWidths}
onColumnResizing={handleColumnResizing}
windowScrollerProps={{ scrollElement: scrollableRef }}
noResults={<RecognizedTransactionsTableNoResults />}
className="table-constrant"
payload={{

View File

@@ -22,6 +22,7 @@ import { useMemorizedColumnsWidths } from '@/hooks';
import { useAccountUncategorizedTransactionsContext } from '../AllTransactionsUncategorizedBoot';
import { useExcludeUncategorizedTransaction } from '@/hooks/query/bank-rules';
import { useAccountUncategorizedTransactionsColumns } from './hooks';
import { useAccountTransactionsContext } from '../AccountTransactionsProvider';
import { compose } from '@/utils';
import { withBanking } from '../../withBanking';
@@ -48,6 +49,8 @@ function AccountTransactionsDataTable({
// Retrieve table columns.
const columns = useAccountUncategorizedTransactionsColumns();
const { scrollableRef } = useAccountTransactionsContext();
// Retrieve list context.
const { uncategorizedTransactions, isUncategorizedTransactionsLoading } =
useAccountUncategorizedTransactionsContext();
@@ -71,6 +74,11 @@ function AccountTransactionsDataTable({
const handleCategorizeBtnClick = (transaction) => {
setUncategorizedTransactionIdForMatching(transaction.id);
};
// handles table selected rows change.
const handleSelectedRowsChange = (selected) => {
const transactionIds = selected.map((r) => r.original.id);
setUncategorizedTransactionsSelected(transactionIds);
};
// Handle exclude transaction.
const handleExcludeTransaction = (transaction) => {
excludeTransaction(transaction.id)
@@ -118,6 +126,8 @@ function AccountTransactionsDataTable({
onExclude: handleExcludeTransaction,
onCategorize: handleCategorizeBtnClick,
}}
onSelectedRowsChange={handleSelectedRowsChange}
windowScrollerProps={{ scrollElement: scrollableRef }}
className={clsx('table-constrant', styles.table, {
[styles.showCategorizeColumn]: enableMultipleCategorization,
})}

View File

@@ -13,21 +13,12 @@ import {
import useApiRequest from '../useRequest';
import { transformToCamelCase } from '@/utils';
import t from './types';
import { BANK_QUERY_KEY } from '@/constants/query-keys/banking';
const QUERY_KEY = {
BANK_RULES: 'BANK_RULE',
BANK_TRANSACTION_MATCHES: 'BANK_TRANSACTION_MATCHES',
RECOGNIZED_BANK_TRANSACTION: 'RECOGNIZED_BANK_TRANSACTION',
EXCLUDED_BANK_TRANSACTIONS_INFINITY: 'EXCLUDED_BANK_TRANSACTIONS_INFINITY',
RECOGNIZED_BANK_TRANSACTIONS_INFINITY:
'RECOGNIZED_BANK_TRANSACTIONS_INFINITY',
BANK_ACCOUNT_SUMMARY_META: 'BANK_ACCOUNT_SUMMARY_META',
AUTOFILL_CATEGORIZE_BANK_TRANSACTION: 'AUTOFILL_CATEGORIZE_BANK_TRANSACTION',
};
// Common cache invalidator.
const commonInvalidateQueries = (query: QueryClient) => {
query.invalidateQueries(QUERY_KEY.BANK_RULES);
query.invalidateQueries(QUERY_KEY.RECOGNIZED_BANK_TRANSACTIONS_INFINITY);
query.invalidateQueries(BANK_QUERY_KEY.BANK_RULES);
query.invalidateQueries(BANK_QUERY_KEY.RECOGNIZED_BANK_TRANSACTIONS_INFINITY);
};
interface CreateBankRuleValues {
@@ -185,7 +176,7 @@ export function useDeleteBankRule(
commonInvalidateQueries(queryClient);
queryClient.invalidateQueries(
QUERY_KEY.RECOGNIZED_BANK_TRANSACTIONS_INFINITY,
BANK_QUERY_KEY.RECOGNIZED_BANK_TRANSACTIONS_INFINITY,
);
queryClient.invalidateQueries([
t.CASHFLOW_ACCOUNT_UNCATEGORIZED_TRANSACTIONS_INFINITY,
@@ -209,7 +200,7 @@ export function useBankRules(
const apiRequest = useApiRequest();
return useQuery<BankRulesResponse, Error>(
[QUERY_KEY.BANK_RULES],
[BANK_QUERY_KEY.BANK_RULES],
() => apiRequest.get('/banking/rules').then((res) => res.data.bank_rules),
{ ...options },
);
@@ -230,7 +221,7 @@ export function useBankRule(
const apiRequest = useApiRequest();
return useQuery<GetBankRuleRes, Error>(
[QUERY_KEY.BANK_RULES, bankRuleId],
[BANK_QUERY_KEY.BANK_RULES, bankRuleId],
() =>
apiRequest
.get(`/banking/rules/${bankRuleId}`)
@@ -260,7 +251,7 @@ export function useGetBankTransactionsMatches(
const apiRequest = useApiRequest();
return useQuery<GetBankTransactionsMatchesResponse, Error>(
[QUERY_KEY.BANK_TRANSACTION_MATCHES, uncategorizeTransactionsIds],
[BANK_QUERY_KEY.BANK_TRANSACTION_MATCHES, uncategorizeTransactionsIds],
() =>
apiRequest
.get(`/cashflow/transactions/matches`, {
@@ -273,7 +264,9 @@ export function useGetBankTransactionsMatches(
const onValidateExcludeUncategorizedTransaction = (queryClient) => {
// Invalidate queries.
queryClient.invalidateQueries(QUERY_KEY.EXCLUDED_BANK_TRANSACTIONS_INFINITY);
queryClient.invalidateQueries(
BANK_QUERY_KEY.EXCLUDED_BANK_TRANSACTIONS_INFINITY,
);
queryClient.invalidateQueries(
t.CASHFLOW_ACCOUNT_UNCATEGORIZED_TRANSACTIONS_INFINITY,
);
@@ -282,7 +275,7 @@ const onValidateExcludeUncategorizedTransaction = (queryClient) => {
queryClient.invalidateQueries(t.ACCOUNT);
// invalidate bank account summary.
queryClient.invalidateQueries(QUERY_KEY.BANK_ACCOUNT_SUMMARY_META);
queryClient.invalidateQueries(BANK_QUERY_KEY.BANK_ACCOUNT_SUMMARY_META);
};
type ExcludeUncategorizedTransactionValue = number;
@@ -319,6 +312,10 @@ export function useExcludeUncategorizedTransaction(
{
onSuccess: (res, id) => {
onValidateExcludeUncategorizedTransaction(queryClient);
queryClient.invalidateQueries([
BANK_QUERY_KEY.BANK_ACCOUNT_SUMMARY_META,
id,
]);
},
...options,
},
@@ -360,6 +357,10 @@ export function useUnexcludeUncategorizedTransaction(
{
onSuccess: (res, id) => {
onValidateExcludeUncategorizedTransaction(queryClient);
queryClient.invalidateQueries([
BANK_QUERY_KEY.BANK_ACCOUNT_SUMMARY_META,
id,
]);
},
...options,
},
@@ -483,7 +484,7 @@ export function useMatchUncategorizedTransaction(
queryClient.invalidateQueries(t.ACCOUNT);
// Invalidate bank account summary.
queryClient.invalidateQueries(QUERY_KEY.BANK_ACCOUNT_SUMMARY_META);
queryClient.invalidateQueries(BANK_QUERY_KEY.BANK_ACCOUNT_SUMMARY_META);
},
...props,
});
@@ -529,7 +530,7 @@ export function useUnmatchMatchedUncategorizedTransaction(
queryClient.invalidateQueries(t.ACCOUNT);
// Invalidate bank account summary.
queryClient.invalidateQueries(QUERY_KEY.BANK_ACCOUNT_SUMMARY_META);
queryClient.invalidateQueries(BANK_QUERY_KEY.BANK_ACCOUNT_SUMMARY_META);
},
...props,
});
@@ -550,7 +551,7 @@ export function useGetRecognizedBankTransaction(
const apiRequest = useApiRequest();
return useQuery<GetRecognizedBankTransactionRes, Error>(
[QUERY_KEY.RECOGNIZED_BANK_TRANSACTION, uncategorizedTransactionId],
[BANK_QUERY_KEY.RECOGNIZED_BANK_TRANSACTION, uncategorizedTransactionId],
() =>
apiRequest
.get(`/banking/recognized/transactions/${uncategorizedTransactionId}`)
@@ -578,7 +579,7 @@ export function useGetBankAccountSummaryMeta(
const apiRequest = useApiRequest();
return useQuery<GetBankAccountSummaryMetaRes, Error>(
[QUERY_KEY.BANK_ACCOUNT_SUMMARY_META, bankAccountId],
[BANK_QUERY_KEY.BANK_ACCOUNT_SUMMARY_META, bankAccountId],
() =>
apiRequest
.get(`/banking/bank_accounts/${bankAccountId}/meta`)
@@ -610,7 +611,7 @@ export function useGetAutofillCategorizeTransaction(
return useQuery<GetAutofillCategorizeTransaction, Error>(
[
QUERY_KEY.AUTOFILL_CATEGORIZE_BANK_TRANSACTION,
BANK_QUERY_KEY.AUTOFILL_CATEGORIZE_BANK_TRANSACTION,
uncategorizedTransactionIds,
],
() =>
@@ -634,7 +635,7 @@ export function useRecognizedBankTransactionsInfinity(
const apiRequest = useApiRequest();
return useInfiniteQuery(
[QUERY_KEY.RECOGNIZED_BANK_TRANSACTIONS_INFINITY, query],
[BANK_QUERY_KEY.RECOGNIZED_BANK_TRANSACTIONS_INFINITY, query],
async ({ pageParam = 1 }) => {
const response = await apiRequest.http({
...axios,
@@ -666,7 +667,7 @@ export function useExcludedBankTransactionsInfinity(
const apiRequest = useApiRequest();
return useInfiniteQuery(
[QUERY_KEY.EXCLUDED_BANK_TRANSACTIONS_INFINITY, query],
[BANK_QUERY_KEY.EXCLUDED_BANK_TRANSACTIONS_INFINITY, query],
async ({ pageParam = 1 }) => {
const response = await apiRequest.http({
...axios,

View File

@@ -9,6 +9,7 @@ import useApiRequest from '../useRequest';
import { transformToCamelCase } from '@/utils';
import { downloadFile, useDownloadFile } from '../useDownloadFile';
import T from './types';
import { BANK_QUERY_KEY } from '@/constants/query-keys/banking';
const QueryKeys = {
ImportPreview: 'ImportPreview',
@@ -127,8 +128,8 @@ export const useSampleSheetImport = () => {
/**
* Invalidates resources cached queries based on the given resource name,
* @param queryClient
* @param resource
* @param queryClient
* @param resource
*/
const invalidateResourcesOnImport = (
queryClient: QueryClient,
@@ -215,6 +216,7 @@ const invalidateResourcesOnImport = (
T.CASHFLOW_ACCOUNT_UNCATEGORIZED_TRANSACTIONS_INFINITY,
);
queryClient.invalidateQueries(T.CASHFLOW_UNCAATEGORIZED_TRANSACTION);
queryClient.invalidateQueries(BANK_QUERY_KEY.BANK_ACCOUNT_SUMMARY_META);
break;
}
};