fix: bank rules

This commit is contained in:
Ahmed Bouhuolia
2024-07-02 12:16:51 +02:00
parent 50861940a8
commit 8a09de9771
15 changed files with 87 additions and 55 deletions

View File

@@ -1,11 +1,11 @@
exports.up = function (knex) {
return knex.schema.table('uncategorized_cashflow_transactions', (table) => {
table.boolean('excluded');
table.datetime('excluded_at');
});
};
exports.down = function (knex) {
return knex.schema.table('uncategorized_cashflow_transactions', (table) => {
table.dropColumn('excluded');
table.dropColumn('excluded_at');
});
};

View File

@@ -98,14 +98,14 @@ export default class UncategorizedCashflowTransaction extends mixin(
* Filters the not excluded transactions.
*/
notExcluded(query) {
query.whereNull('excluded');
query.whereNull('excluded_at');
},
/**
* Filters the excluded transactions.
*/
excluded(query) {
query.where('excluded', true)
query.whereNotNull('excluded_at')
}
};
},

View File

@@ -34,7 +34,7 @@ export class ExcludeBankTransaction {
await UncategorizedCashflowTransaction.query(trx)
.findById(uncategorizedTransactionId)
.patch({
excluded: true,
excludedAt: new Date(),
});
});
}

View File

@@ -33,7 +33,7 @@ export class GetExcludedBankTransactionsService {
const { results, pagination } =
await UncategorizedCashflowTransaction.query()
.onBuild((q) => {
q.where('excluded', true);
q.modify('excluded');
q.orderBy('date', 'DESC');
if (_query.accountId) {

View File

@@ -34,7 +34,7 @@ export class UnexcludeBankTransaction {
await UncategorizedCashflowTransaction.query(trx)
.findById(uncategorizedTransactionId)
.patch({
excluded: null,
excludedAt: null,
});
});
}

View File

@@ -1,6 +1,6 @@
// @ts-nocheck
import { Form, Formik, FormikHelpers, useFormikContext } from 'formik';
import { Button, Classes, Intent, Radio } from '@blueprintjs/core';
import { Button, Classes, Intent, Radio, Tag } from '@blueprintjs/core';
import * as R from 'ramda';
import { CreateRuleFormSchema } from './RuleFormContentForm.schema';
import {
@@ -73,7 +73,7 @@ function RuleFormContentFormRoot({
});
};
if (isEditMode) {
editBankRule([bankRuleId, _values])
editBankRule({ id: bankRuleId, value: _values })
.then(handleSuccess)
.catch(handleError);
} else {
@@ -88,16 +88,26 @@ function RuleFormContentFormRoot({
onSubmit={handleSubmit}
>
<Form>
<FFormGroup name={'name'} label={'Rule Name'} style={{ maxWidth: 300 }}>
<FFormGroup
name={'name'}
label={'Rule Name'}
labelInfo={<Tag minimal>Required</Tag>}
style={{ maxWidth: 300 }}
>
<FInputGroup name={'name'} />
</FFormGroup>
<FFormGroup
name={'applyIfAccountId'}
label={'Apply the rule to account'}
labelInfo={<Tag minimal>Required</Tag>}
style={{ maxWidth: 350 }}
>
<AccountsSelect name={'applyIfAccountId'} items={accounts} />
<AccountsSelect
name={'applyIfAccountId'}
items={accounts}
filterByTypes={['cash', 'bank']}
/>
</FFormGroup>
<FFormGroup
@@ -133,6 +143,7 @@ function RuleFormContentFormRoot({
<FFormGroup
name={'assignCategory'}
label={'Transaction type'}
labelInfo={<Tag minimal>Required</Tag>}
style={{ maxWidth: 300 }}
>
<FSelect
@@ -145,6 +156,7 @@ function RuleFormContentFormRoot({
<FFormGroup
name={'assignAccountId'}
label={'Account category'}
labelInfo={<Tag minimal>Required</Tag>}
style={{ maxWidth: 300 }}
>
<AccountsSelect name={'assignAccountId'} items={accounts} />
@@ -251,6 +263,7 @@ function RuleFormActionsRoot({
<Box className={Classes.DIALOG_FOOTER_ACTIONS}>
<Button onClick={handleCancelBtnClick}>Cancel</Button>
<Button
type="submit"
intent={Intent.PRIMARY}
loading={isSubmitting}
onClick={handleSaveBtnClick}

View File

@@ -6,6 +6,11 @@ import {
Classes,
NavbarDivider,
Alignment,
Popover,
Menu,
MenuItem,
PopoverInteractionKind,
Position,
} from '@blueprintjs/core';
import { useHistory } from 'react-router-dom';
import {
@@ -39,18 +44,20 @@ function AccountTransactionsActionsBar({
// #withSettingsActions
addSetting,
}) {
// Handle table row size change.
const handleTableRowSizeChange = (size) => {
addSetting('cashflowTransactions', 'tableSize', size);
};
const history = useHistory();
const { accountId } = useAccountTransactionsContext();
// Refresh cashflow infinity transactions hook.
const { refresh } = useRefreshCashflowTransactionsInfinity();
// Retrieves the money in/out buttons options.
const addMoneyInOptions = useMemo(() => getAddMoneyInOptions(), []);
const addMoneyOutOptions = useMemo(() => getAddMoneyOutOptions(), []);
const history = useHistory();
// Handle table row size change.
const handleTableRowSizeChange = (size) => {
addSetting('cashflowTransactions', 'tableSize', size);
};
// Handle money in form
const handleMoneyInFormTransaction = (account) => {
openDialog('money-in', {
@@ -71,10 +78,10 @@ function AccountTransactionsActionsBar({
const handleImportBtnClick = () => {
history.push(`/cashflow-accounts/${accountId}/import`);
};
// Refresh cashflow infinity transactions hook.
const { refresh } = useRefreshCashflowTransactionsInfinity();
// Handle bank rules click.
const handleBankRulesClick = () => {
history.push(`/bank-rules?accountId=${accountId}`);
};
// Handle the refresh button click.
const handleRefreshBtnClick = () => {
refresh();
@@ -125,6 +132,22 @@ function AccountTransactionsActionsBar({
</NavbarGroup>
<NavbarGroup align={Alignment.RIGHT}>
<Popover
minimal={true}
interactionKind={PopoverInteractionKind.CLICK}
position={Position.BOTTOM_LEFT}
modifiers={{
offset: { offset: '0, 4' },
}}
content={
<Menu>
<MenuItem onClick={handleBankRulesClick} text={'Bank rules'} />
</Menu>
}
>
<Button icon={<Icon icon="cog-16" iconSize={16} />} minimal={true} />
</Popover>
<NavbarDivider />
<Button
className={Classes.MINIMAL}
icon={<Icon icon="refresh-16" iconSize={14} />}

View File

@@ -18,10 +18,10 @@ import withDrawerActions from '@/containers/Drawer/withDrawerActions';
import { useMemorizedColumnsWidths } from '@/hooks';
import { useAccountTransactionsColumns, ActionsMenu } from './components';
import { useAccountTransactionsAllContext } from './AccountTransactionsAllBoot';
import { handleCashFlowTransactionType } from './utils';
import { compose } from '@/utils';
import { useAccountTransactionsAllContext } from './AccountTransactionsAllBoot';
/**
* Account transactions data table.
@@ -108,7 +108,6 @@ const DashboardConstrantTable = styled(DataTable)`
background: #fff;
letter-spacing: 1px;
text-transform: uppercase;
font-weight: 500;
font-size: 13px;
}
}

View File

@@ -9,7 +9,7 @@ const Root = styled.div`
display: flex;
flex-direction: row;
gap: 10px;
margin-bottom: 18px;
margin-bottom: 14px;
`;
const FilterTag = styled(Tag)`

View File

@@ -59,6 +59,10 @@ function AccountTransactionsDataTable({
const handleCellClick = (cell) => {
setUncategorizedTransactionIdForMatching(cell.row.original.id);
};
// Handles categorize button click.
const handleCategorizeBtnClick = (transaction) => {
setUncategorizedTransactionIdForMatching(transaction.id);
};
// Handle exclude transaction.
const handleExcludeTransaction = (transaction) => {
excludeTransaction(transaction.id)
@@ -102,6 +106,7 @@ function AccountTransactionsDataTable({
className="table-constrant"
payload={{
onExclude: handleExcludeTransaction,
onCategorize: handleCategorizeBtnClick,
}}
/>
);

View File

@@ -23,12 +23,10 @@ import { ActionsMenu } from './_components';
import { useUnexcludeUncategorizedTransaction } from '@/hooks/query/bank-rules';
import { Intent } from '@blueprintjs/core';
interface ExcludedTransactionsTableProps {}
/**
* Renders the recognized account transactions datatable.
*/
function ExcludedTransactionsTableRoot({}: ExcludedTransactionsTableProps) {
function ExcludedTransactionsTableRoot() {
const { excludedBankTransactions } = useExcludedTransactionsBoot();
const { mutateAsync: unexcludeBankTransaction } =
useUnexcludeUncategorizedTransaction();
@@ -103,7 +101,6 @@ const DashboardConstrantTable = styled(DataTable)`
background: #fff;
letter-spacing: 1px;
text-transform: uppercase;
font-weight: 500;
font-size: 13px;
}
}

View File

@@ -84,7 +84,7 @@ function RecognizedTransactionsTableRoot({
});
};
//
// Handles categorize button click.
const handleCategorizeClick = (transaction) => {
setUncategorizedTransactionIdForMatching(
transaction.uncategorized_transaction_id,
@@ -137,7 +137,6 @@ const DashboardConstrantTable = styled(DataTable)`
background: #fff;
letter-spacing: 1px;
text-transform: uppercase;
font-weight: 500;
font-size: 13px;
}
}

View File

@@ -11,6 +11,7 @@ export function ActionsMenu({
<Menu>
<MenuItem
text={'Categorize'}
icon={<Icon icon="reader-18" />}
onClick={safeCallback(onCategorize, original)}
/>
<MenuDivider />

View File

@@ -1,41 +1,22 @@
// @ts-nocheck
import React from 'react';
import intl from 'react-intl-universal';
import { Intent, Menu, MenuItem, MenuDivider } from '@blueprintjs/core';
import {
Can,
FormatDateCell,
If,
Icon,
MaterialProgressBar,
} from '@/components';
import { Intent, Menu, MenuItem, MenuDivider, Tag } from '@blueprintjs/core';
import { Can, FormatDateCell, Icon, MaterialProgressBar } from '@/components';
import { useAccountTransactionsContext } from './AccountTransactionsProvider';
import { TRANSACRIONS_TYPE } from '@/constants/cashflowOptions';
import { AbilitySubject, CashflowAction } from '@/constants/abilityOption';
import { safeCallback } from '@/utils';
export function ActionsMenu({
payload: { onDelete, onViewDetails, onExclude },
payload: { onCategorize, onExclude },
row: { original },
}) {
return (
<Menu>
<MenuItem
icon={<Icon icon="reader-18" />}
text={intl.get('view_details')}
onClick={safeCallback(onViewDetails, original)}
text={'Categorize'}
onClick={safeCallback(onCategorize, original)}
/>
<Can I={CashflowAction.Delete} a={AbilitySubject.Cashflow}>
<If condition={TRANSACRIONS_TYPE.includes(original.reference_type)}>
<MenuDivider />
<MenuItem
text={intl.get('delete_transaction')}
intent={Intent.DANGER}
onClick={safeCallback(onDelete, original)}
icon={<Icon icon="trash-16" iconSize={16} />}
/>
</If>
</Can>
<MenuDivider />
<MenuItem
text={'Exclude'}
@@ -186,6 +167,20 @@ export function useAccountUncategorizedTransactionsColumns() {
clickable: true,
textOverview: true,
},
{
id: 'status',
Header: 'Status',
accessor: () =>
false ? (
<Tag intent={Intent.SUCCESS} interactive>
1 Matches
</Tag>
) : (
<Tag intent={Intent.SUCCESS} interactive>
Recognized
</Tag>
),
},
{
id: 'deposit',
Header: intl.get('cash_flow.label.deposit'),

View File

@@ -78,7 +78,7 @@ export function useEditBankRule(
const apiRequest = useApiRequest();
return useMutation<EditBankRuleResponse, Error, EditBankRuleValues>(
({ id, value }) => apiRequest.post(`/banking/rules/${id}`, values),
({ id, value }) => apiRequest.post(`/banking/rules/${id}`, value),
{
...options,
onSuccess: () => {