diff --git a/packages/server/src/api/controllers/Banking/BankingRulesController.ts b/packages/server/src/api/controllers/Banking/BankingRulesController.ts index e7608f56d..008b753d9 100644 --- a/packages/server/src/api/controllers/Banking/BankingRulesController.ts +++ b/packages/server/src/api/controllers/Banking/BankingRulesController.ts @@ -33,7 +33,16 @@ export class BankingRulesController extends BaseController { body('conditions.*.field').exists().isIn(['description', 'amount']), body('conditions.*.comparator') .exists() - .isIn(['equals', 'contains', 'not_contain']) + .isIn([ + 'equals', + 'equal', + 'contains', + 'not_contain', + 'bigger', + 'bigger_or_equal', + 'smaller', + 'smaller_or_equal', + ]) .default('contain') .trim(), body('conditions.*.value').exists().trim(), diff --git a/packages/server/src/services/Banking/RegonizeTranasctions/_utils.ts b/packages/server/src/services/Banking/RegonizeTranasctions/_utils.ts index 1eaa546ec..a69aebe5f 100644 --- a/packages/server/src/services/Banking/RegonizeTranasctions/_utils.ts +++ b/packages/server/src/services/Banking/RegonizeTranasctions/_utils.ts @@ -33,17 +33,29 @@ const matchNumberCondition = ( transaction: UncategorizedCashflowTransaction, condition: IBankRuleCondition ) => { + const conditionValue = parseFloat(condition.value); + const transactionAmount = + condition.field === 'amount' + ? Math.abs(transaction[condition.field]) + : (transaction[condition.field] as unknown as number); + switch (condition.comparator) { case BankRuleConditionComparator.Equals: - return transaction[condition.field] === condition.value; - case BankRuleConditionComparator.Contains: - return transaction[condition.field] - ?.toString() - .includes(condition.value.toString()); - case BankRuleConditionComparator.NotContain: - return !transaction[condition.field] - ?.toString() - .includes(condition.value.toString()); + case BankRuleConditionComparator.Equal: + return transactionAmount === conditionValue; + + case BankRuleConditionComparator.BiggerOrEqual: + return transactionAmount >= conditionValue; + + case BankRuleConditionComparator.Bigger: + return transactionAmount > conditionValue; + + case BankRuleConditionComparator.Smaller: + return transactionAmount < conditionValue; + + case BankRuleConditionComparator.SmallerOrEqual: + return transactionAmount <= conditionValue; + default: return false; } @@ -53,18 +65,19 @@ const matchTextCondition = ( transaction: UncategorizedCashflowTransaction, condition: IBankRuleCondition ): boolean => { + const transactionValue = transaction[condition.field] as string; + switch (condition.comparator) { case BankRuleConditionComparator.Equals: - return transaction[condition.field] === condition.value; + case BankRuleConditionComparator.Equal: + return transactionValue === condition.value; case BankRuleConditionComparator.Contains: - const fieldValue = lowerCase(transaction[condition.field]); + const fieldValue = lowerCase(transactionValue); const conditionValue = lowerCase(condition.value); return fieldValue.includes(conditionValue); case BankRuleConditionComparator.NotContain: - return !transaction[condition.field]?.includes( - condition.value.toString() - ); + return !transactionValue?.includes(condition.value.toString()); default: return false; } @@ -101,8 +114,8 @@ const determineFieldType = (field: string): string => { case 'amount': return 'number'; case 'description': - return 'text'; + case 'payee': default: return 'unknown'; } -}; \ No newline at end of file +}; diff --git a/packages/server/src/services/Banking/Rules/types.ts b/packages/server/src/services/Banking/Rules/types.ts index d54cb9388..7f8bb6cbc 100644 --- a/packages/server/src/services/Banking/Rules/types.ts +++ b/packages/server/src/services/Banking/Rules/types.ts @@ -1,15 +1,20 @@ import { Knex } from 'knex'; export enum BankRuleConditionField { - Amount = 'Amount', - Description = 'Description', - Payee = 'Payee', + Amount = 'amount', + Description = 'description', + Payee = 'payee', } export enum BankRuleConditionComparator { Contains = 'contains', Equals = 'equals', + Equal = 'equal', NotContain = 'not_contain', + Bigger = 'bigger', + BiggerOrEqual = 'bigger_or_equal', + Smaller = 'smaller', + SmallerOrEqual = 'smaller_or_equal', } export interface IBankRuleCondition { @@ -56,7 +61,13 @@ export enum BankRuleAssignCategory { export interface IBankRuleConditionDTO { id?: number; field: string; - comparator: string; + comparator: + | 'contains' + | 'equals' + | 'not_contains' + | 'smaller' + | 'bigger_or_equal' + | 'smaller_or_equal'; value: number; } diff --git a/packages/webapp/src/containers/Banking/Rules/RuleFormDialog/RuleFormContentForm.tsx b/packages/webapp/src/containers/Banking/Rules/RuleFormDialog/RuleFormContentForm.tsx index 96b5f4364..b27b86f50 100644 --- a/packages/webapp/src/containers/Banking/Rules/RuleFormDialog/RuleFormContentForm.tsx +++ b/packages/webapp/src/containers/Banking/Rules/RuleFormDialog/RuleFormContentForm.tsx @@ -17,11 +17,12 @@ import { } from '@/components'; import { useCreateBankRule, useEditBankRule } from '@/hooks/query/bank-rules'; import { - FieldCondition, Fields, RuleFormValues, TransactionTypeOptions, getAccountRootFromMoneyCategory, + getDefaultFieldConditionByFieldKey, + getFieldConditionsByFieldKey, initialValues, } from './_utils'; import { useRuleFormDialogBoot } from './RuleFormBoot'; @@ -33,6 +34,7 @@ import { import withDialogActions from '@/containers/Dialog/withDialogActions'; import { DialogsName } from '@/constants/dialogs'; import { getAddMoneyInOptions, getAddMoneyOutOptions } from '@/constants'; +import { get } from 'lodash'; // Retrieves the add money in button options. const MoneyInOptions = getAddMoneyInOptions(); @@ -175,6 +177,13 @@ function RuleFormConditions() { setFieldValue('conditions', _conditions); }; + const handleConditionFieldChange = (item) => { + const defaultComparator = getDefaultFieldConditionByFieldKey(item.value); + + setFieldValue(`conditions[${index}].field`, item.value); + setFieldValue(`conditions[${index}].comparator`, defaultComparator); + }; + return ( @@ -190,6 +199,7 @@ function RuleFormConditions() { name={`conditions[${index}].field`} items={Fields} popoverProps={{ minimal: true, inline: false }} + onItemChange={handleConditionFieldChange} fastField /> @@ -202,8 +212,13 @@ function RuleFormConditions() { > diff --git a/packages/webapp/src/containers/Banking/Rules/RuleFormDialog/_utils.ts b/packages/webapp/src/containers/Banking/Rules/RuleFormDialog/_utils.ts index db77154e9..343d9d5a3 100644 --- a/packages/webapp/src/containers/Banking/Rules/RuleFormDialog/_utils.ts +++ b/packages/webapp/src/containers/Banking/Rules/RuleFormDialog/_utils.ts @@ -42,11 +42,24 @@ export const Fields = [ { value: 'amount', text: 'Amount' }, { value: 'payee', text: 'Payee' }, ]; -export const FieldCondition = [ + +export const TextFieldConditions = [ { value: 'contains', text: 'Contains' }, { value: 'equals', text: 'Equals' }, { value: 'not_contains', text: 'Not Contains' }, ]; +export const NumberFieldConditions = [ + { value: 'bigger', text: 'Bigger' }, + { value: 'bigger_or_equal', text: 'Bigger or Equal' }, + { value: 'smaller', text: 'Smaller' }, + { value: 'smaller_or_equal', text: 'Smaller or Equal' }, +]; + +export const FieldCondition = [ + ...TextFieldConditions, + ...NumberFieldConditions, +]; + export const AssignTransactionTypeOptions = [ { value: 'expense', text: 'Expense' }, ]; @@ -56,3 +69,21 @@ export const getAccountRootFromMoneyCategory = (category: string): string[] => { return get(MoneyCategoryPerCreditAccountRootType, _category) || []; }; + +export const getFieldConditionsByFieldKey = (fieldKey?: string) => { + switch (fieldKey) { + case 'amount': + return NumberFieldConditions; + default: + return TextFieldConditions; + } +}; + +export const getDefaultFieldConditionByFieldKey = (fieldKey?: string) => { + switch (fieldKey) { + case 'amount': + return 'bigger_or_equal'; + default: + return 'equals'; + } +};