fix: add bank rule categories

This commit is contained in:
Ahmed Bouhuolia
2024-07-08 21:48:16 +02:00
parent 38d4122d11
commit 73acdb6240
3 changed files with 143 additions and 38 deletions

View File

@@ -39,3 +39,12 @@ export const TRANSACRIONS_TYPE = [
'OtherExpense', 'OtherExpense',
'TransferToAccount', 'TransferToAccount',
]; ];
export const MoneyCategoryPerCreditAccountRootType = {
OwnerContribution: ['equity'],
OtherIncome: ['income'],
OwnerDrawing: ['equity'],
OtherExpense: ['expense'],
TransferToAccount: ['asset'],
TransferFromAccount: ['asset'],
};

View File

@@ -1,4 +1,5 @@
// @ts-nocheck // @ts-nocheck
import { useCallback, useMemo } from 'react';
import { Form, Formik, FormikHelpers, useFormikContext } from 'formik'; import { Form, Formik, FormikHelpers, useFormikContext } from 'formik';
import { Button, Classes, Intent, Radio, Tag } from '@blueprintjs/core'; import { Button, Classes, Intent, Radio, Tag } from '@blueprintjs/core';
import * as R from 'ramda'; import * as R from 'ramda';
@@ -16,11 +17,11 @@ import {
} from '@/components'; } from '@/components';
import { useCreateBankRule, useEditBankRule } from '@/hooks/query/bank-rules'; import { useCreateBankRule, useEditBankRule } from '@/hooks/query/bank-rules';
import { import {
AssignTransactionTypeOptions,
FieldCondition, FieldCondition,
Fields, Fields,
RuleFormValues, RuleFormValues,
TransactionTypeOptions, TransactionTypeOptions,
getAccountRootFromMoneyCategory,
initialValues, initialValues,
} from './_utils'; } from './_utils';
import { useRuleFormDialogBoot } from './RuleFormBoot'; import { useRuleFormDialogBoot } from './RuleFormBoot';
@@ -31,6 +32,11 @@ import {
} from '@/utils'; } from '@/utils';
import withDialogActions from '@/containers/Dialog/withDialogActions'; import withDialogActions from '@/containers/Dialog/withDialogActions';
import { DialogsName } from '@/constants/dialogs'; import { DialogsName } from '@/constants/dialogs';
import { getAddMoneyInOptions, getAddMoneyOutOptions } from '@/constants';
// Retrieves the add money in button options.
const MoneyInOptions = getAddMoneyInOptions();
const MoneyOutOptions = getAddMoneyOutOptions();
function RuleFormContentFormRoot({ function RuleFormContentFormRoot({
// #withDialogActions // #withDialogActions
@@ -47,7 +53,6 @@ function RuleFormContentFormRoot({
...initialValues, ...initialValues,
...transformToForm(transformToCamelCase(bankRule), initialValues), ...transformToForm(transformToCamelCase(bankRule), initialValues),
}; };
// Handles the form submitting. // Handles the form submitting.
const handleSubmit = ( const handleSubmit = (
values: RuleFormValues, values: RuleFormValues,
@@ -92,8 +97,9 @@ function RuleFormContentFormRoot({
label={'Rule Name'} label={'Rule Name'}
labelInfo={<Tag minimal>Required</Tag>} labelInfo={<Tag minimal>Required</Tag>}
style={{ maxWidth: 300 }} style={{ maxWidth: 300 }}
fastField
> >
<FInputGroup name={'name'} /> <FInputGroup name={'name'} fastField />
</FFormGroup> </FFormGroup>
<FFormGroup <FFormGroup
@@ -101,29 +107,22 @@ function RuleFormContentFormRoot({
label={'Apply the rule to account'} label={'Apply the rule to account'}
labelInfo={<Tag minimal>Required</Tag>} labelInfo={<Tag minimal>Required</Tag>}
style={{ maxWidth: 350 }} style={{ maxWidth: 350 }}
fastField
> >
<AccountsSelect <AccountsSelect
name={'applyIfAccountId'} name={'applyIfAccountId'}
items={accounts} items={accounts}
filterByTypes={['cash', 'bank']} filterByTypes={['cash', 'bank']}
fastField
/> />
</FFormGroup> </FFormGroup>
<FFormGroup <RuleApplyIfTransactionTypeField />
name={'applyIfTransactionType'}
label={'Apply to transactions are'}
style={{ maxWidth: 350 }}
>
<FSelect
name={'applyIfTransactionType'}
items={TransactionTypeOptions}
popoverProps={{ minimal: true, inline: false }}
/>
</FFormGroup>
<FFormGroup <FFormGroup
name={'conditionsType'} name={'conditionsType'}
label={'Categorize the transactions when'} label={'Categorize the transactions when'}
fastField
> >
<FRadioGroup name={'conditionsType'}> <FRadioGroup name={'conditionsType'}>
<Radio value={'and'} label={'All the following criteria matches'} /> <Radio value={'and'} label={'All the following criteria matches'} />
@@ -139,34 +138,16 @@ function RuleFormContentFormRoot({
Then Assign Then Assign
</h3> </h3>
<FFormGroup <RuleAssignCategoryField />
name={'assignCategory'} <RuleAssignCategoryAccountField />
label={'Transaction type'}
labelInfo={<Tag minimal>Required</Tag>}
style={{ maxWidth: 300 }}
>
<FSelect
name={'assignCategory'}
items={AssignTransactionTypeOptions}
popoverProps={{ minimal: true, inline: false }}
/>
</FFormGroup>
<FFormGroup
name={'assignAccountId'}
label={'Account category'}
labelInfo={<Tag minimal>Required</Tag>}
style={{ maxWidth: 300 }}
>
<AccountsSelect name={'assignAccountId'} items={accounts} />
</FFormGroup>
<FFormGroup <FFormGroup
name={'assignRef'} name={'assignRef'}
label={'Reference'} label={'Reference'}
style={{ maxWidth: 300 }} style={{ maxWidth: 300 }}
fastField
> >
<FInputGroup name={'assignRef'} /> <FInputGroup name={'assignRef'} fastField />
</FFormGroup> </FFormGroup>
<RuleFormActions /> <RuleFormActions />
@@ -203,11 +184,13 @@ function RuleFormConditions() {
name={`conditions[${index}].field`} name={`conditions[${index}].field`}
label={'Field'} label={'Field'}
style={{ marginBottom: 0, flex: '1 0' }} style={{ marginBottom: 0, flex: '1 0' }}
fastField
> >
<FSelect <FSelect
name={`conditions[${index}].field`} name={`conditions[${index}].field`}
items={Fields} items={Fields}
popoverProps={{ minimal: true, inline: false }} popoverProps={{ minimal: true, inline: false }}
fastField
/> />
</FFormGroup> </FFormGroup>
@@ -215,11 +198,13 @@ function RuleFormConditions() {
name={`conditions[${index}].comparator`} name={`conditions[${index}].comparator`}
label={'Condition'} label={'Condition'}
style={{ marginBottom: 0, flex: '1 0' }} style={{ marginBottom: 0, flex: '1 0' }}
fastField
> >
<FSelect <FSelect
name={`conditions[${index}].comparator`} name={`conditions[${index}].comparator`}
items={FieldCondition} items={FieldCondition}
popoverProps={{ minimal: true, inline: false }} popoverProps={{ minimal: true, inline: false }}
fastField
/> />
</FFormGroup> </FFormGroup>
@@ -227,8 +212,9 @@ function RuleFormConditions() {
name={`conditions[${index}].value`} name={`conditions[${index}].value`}
label={'Value'} label={'Value'}
style={{ marginBottom: 0, flex: '1 0 ', width: '40%' }} style={{ marginBottom: 0, flex: '1 0 ', width: '40%' }}
fastField
> >
<FInputGroup name={`conditions[${index}].value`} /> <FInputGroup name={`conditions[${index}].value`} fastField />
</FFormGroup> </FFormGroup>
</Group> </Group>
))} ))}
@@ -284,3 +270,104 @@ function RuleFormActionsRoot({
} }
const RuleFormActions = R.compose(withDialogActions)(RuleFormActionsRoot); const RuleFormActions = R.compose(withDialogActions)(RuleFormActionsRoot);
function RuleApplyIfTransactionTypeField() {
const { setFieldValue } = useFormikContext<RuleFormValues>();
const handleItemChange = useCallback(
(item: any) => {
setFieldValue('applyIfTransactionType', item.value);
setFieldValue('assignCategory', '');
setFieldValue('assignAccountId', '');
},
[setFieldValue],
);
return (
<FFormGroup
name={'applyIfTransactionType'}
label={'Apply to transactions are'}
style={{ maxWidth: 350 }}
fastField
>
<FSelect
name={'applyIfTransactionType'}
items={TransactionTypeOptions}
popoverProps={{ minimal: true, inline: false }}
onItemChange={handleItemChange}
fastField
/>
</FFormGroup>
);
}
function RuleAssignCategoryField() {
const { values, setFieldValue } = useFormikContext<RuleFormValues>();
// Retrieves the transaction types if it is deposit or withdrawal.
const transactionTypes = useMemo(
() =>
values?.applyIfTransactionType === 'deposit'
? MoneyInOptions
: MoneyOutOptions,
[values?.applyIfTransactionType],
);
// Handles the select item change.
const handleItemChange = useCallback(
(item: any) => {
setFieldValue('assignCategory', item.value);
setFieldValue('assignAccountId', '');
},
[setFieldValue],
);
return (
<FFormGroup
name={'assignCategory'}
label={'Transaction type'}
labelInfo={<Tag minimal>Required</Tag>}
style={{ maxWidth: 300 }}
fastField
>
<FSelect
name={'assignCategory'}
items={transactionTypes}
popoverProps={{ minimal: true, inline: false }}
valueAccessor={'value'}
textAccessor={'name'}
onItemChange={handleItemChange}
fastField
/>
</FFormGroup>
);
}
function RuleAssignCategoryAccountField() {
const { values } = useFormikContext<RuleFormValues>();
const { accounts } = useRuleFormDialogBoot();
const accountRoot = useMemo(
() => getAccountRootFromMoneyCategory(values.assignCategory),
[values.assignCategory],
);
return (
<FFormGroup
name={'assignAccountId'}
label={'Account category'}
labelInfo={<Tag minimal>Required</Tag>}
style={{ maxWidth: 300 }}
fastField
shouldUpdateDeps={{ accountRoot }}
>
<AccountsSelect
name={'assignAccountId'}
items={accounts}
filterByRootTypes={accountRoot}
shouldUpdateDeps={{ accountRoot }}
fastField
/>
</FFormGroup>
);
}

View File

@@ -1,8 +1,11 @@
import { camelCase, get, upperFirst } from 'lodash';
import { MoneyCategoryPerCreditAccountRootType } from '@/constants/cashflowOptions';
export const initialValues = { export const initialValues = {
name: '', name: '',
order: 0, order: 0,
applyIfAccountId: '', applyIfAccountId: '',
applyIfTransactionType: '', applyIfTransactionType: 'deposit',
conditionsType: 'and', conditionsType: 'and',
conditions: [ conditions: [
{ {
@@ -47,3 +50,9 @@ export const FieldCondition = [
export const AssignTransactionTypeOptions = [ export const AssignTransactionTypeOptions = [
{ value: 'expense', text: 'Expense' }, { value: 'expense', text: 'Expense' },
]; ];
export const getAccountRootFromMoneyCategory = (category: string): string[] => {
const _category = upperFirst(camelCase(category));
return get(MoneyCategoryPerCreditAccountRootType, _category) || [];
};