diff --git a/apps/fyle/constants.py b/apps/fyle/constants.py index 2171b9aa..a8a6f67b 100644 --- a/apps/fyle/constants.py +++ b/apps/fyle/constants.py @@ -18,5 +18,10 @@ 'field_name': 'spent_at', 'type': 'DATE', 'is_custom': False - } + }, + { + 'field_name': 'category', + 'type': 'SELECT', + 'is_custom': False + }, ] diff --git a/apps/fyle/helpers.py b/apps/fyle/helpers.py index 23002b21..5ed46fe5 100644 --- a/apps/fyle/helpers.py +++ b/apps/fyle/helpers.py @@ -346,7 +346,9 @@ def construct_expense_filter(expense_filter: ExpenseFilter): else: if expense_filter.custom_field_type == 'NUMBER': expense_filter.values = [int(expense_filter_value) for expense_filter_value in expense_filter.values] - + # If the expense filter is a custom field and the operator is yes or no(checkbox) + if expense_filter.custom_field_type == 'BOOLEAN': + expense_filter.values[0] = True if expense_filter.values[0] == 'true' else False filter1 = { 'custom_properties__{0}__{1}'.format( expense_filter.condition, @@ -374,6 +376,14 @@ def construct_expense_filter(expense_filter: ExpenseFilter): #if isnull=False constructed_expense_filter = ~Q(**filter2) + elif expense_filter.condition == 'category' and expense_filter.operator == 'not_in' and not expense_filter.is_custom: + # construct the filter + filter1 = { + f'{expense_filter.condition}__in': expense_filter.values + } + # Invert the filter using the ~Q operator and assign it to the constructed expense filter + constructed_expense_filter = ~Q(**filter1) + else: #This block is for all the non-custom-fields filter1 = { diff --git a/apps/fyle/migrations/0032_alter_expensefilter_custom_field_type.py b/apps/fyle/migrations/0032_alter_expensefilter_custom_field_type.py new file mode 100644 index 00000000..7fb717b9 --- /dev/null +++ b/apps/fyle/migrations/0032_alter_expensefilter_custom_field_type.py @@ -0,0 +1,18 @@ +# Generated by Django 3.2.14 on 2024-05-14 13:47 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fyle', '0031_alter_expensegroupsettings_expense_state'), + ] + + operations = [ + migrations.AlterField( + model_name='expensefilter', + name='custom_field_type', + field=models.CharField(choices=[('SELECT', 'SELECT'), ('NUMBER', 'NUMBER'), ('TEXT', 'TEXT'), ('BOOLEAN', 'BOOLEAN')], help_text='Custom field type', max_length=255, null=True), + ), + ] diff --git a/apps/fyle/models.py b/apps/fyle/models.py index b0cf9327..d7f27c8e 100644 --- a/apps/fyle/models.py +++ b/apps/fyle/models.py @@ -58,7 +58,8 @@ EXPENSE_FILTER_CUSTOM_FIELD_TYPE = ( ('SELECT', 'SELECT'), ('NUMBER', 'NUMBER'), - ('TEXT','TEXT') + ('TEXT','TEXT'), + ('BOOLEAN', 'BOOLEAN') ) EXPENSE_FILTER_OPERATOR = ( diff --git a/apps/fyle/views.py b/apps/fyle/views.py index 7f743f48..300e4931 100644 --- a/apps/fyle/views.py +++ b/apps/fyle/views.py @@ -404,7 +404,7 @@ def get(self, request, *args, **kwargs): response.extend(DEFAULT_FYLE_CONDITIONS) for custom_field in custom_fields: - if custom_field['type'] in ('SELECT', 'NUMBER', 'TEXT'): + if custom_field['type'] in ('SELECT', 'NUMBER', 'TEXT', 'BOOLEAN'): response.append({ 'field_name': custom_field['field_name'], 'type': custom_field['type'], diff --git a/tests/sql_fixtures/reset_db_fixtures/reset_db.sql b/tests/sql_fixtures/reset_db_fixtures/reset_db.sql index 3aa0c498..6413ea3f 100644 --- a/tests/sql_fixtures/reset_db_fixtures/reset_db.sql +++ b/tests/sql_fixtures/reset_db_fixtures/reset_db.sql @@ -946,7 +946,7 @@ CREATE TABLE public.expense_group_settings ( id integer NOT NULL, reimbursable_expense_group_fields character varying(100)[] NOT NULL, corporate_credit_card_expense_group_fields character varying(100)[] NOT NULL, - expense_state character varying(100) NOT NULL, + expense_state character varying(100), reimbursable_export_date_type character varying(100) NOT NULL, created_at timestamp with time zone NOT NULL, updated_at timestamp with time zone NOT NULL, @@ -7969,6 +7969,8 @@ COPY public.django_migrations (id, app, name, applied) FROM stdin; 191 mappings 0014_auto_20240417_0807 2024-05-02 14:31:12.700593+00 192 tasks 0010_auto_20240429_1101 2024-05-02 14:31:12.726708+00 193 tasks 0011_error_repetition_count 2024-05-02 14:31:12.771103+00 +194 fyle 0031_alter_expensegroupsettings_expense_state 2024-05-14 13:47:37.712292+00 +195 fyle 0032_alter_expensefilter_custom_field_type 2024-05-14 13:47:37.73285+00 \. @@ -11880,7 +11882,7 @@ SELECT pg_catalog.setval('public.django_content_type_id_seq', 47, true); -- Name: django_migrations_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres -- -SELECT pg_catalog.setval('public.django_migrations_id_seq', 193, true); +SELECT pg_catalog.setval('public.django_migrations_id_seq', 195, true); -- diff --git a/tests/test_fyle/test_helpers.py b/tests/test_fyle/test_helpers.py index d626cfec..de3d0632 100644 --- a/tests/test_fyle/test_helpers.py +++ b/tests/test_fyle/test_helpers.py @@ -306,6 +306,34 @@ def test_construct_expense_filter(mocker, add_fyle_credentials): filter_1 = {'spent_at__lte':'2020-04-20 23:59:59+00'} response = Q(**filter_1) + # category_in + expense_filter = ExpenseFilter( + condition = 'category', + operator = 'in', + values = ['anish'], + rank = 1 + ) + constructed_expense_filter = construct_expense_filter(expense_filter) + + filter_1 = {'category__in':['anish']} + response = Q(**filter_1) + + assert constructed_expense_filter == response + + # category_not_in + expense_filter = ExpenseFilter( + condition = 'category', + operator = 'not_in', + values = ['anish', 'singh'], + rank = 1 + ) + constructed_expense_filter = construct_expense_filter(expense_filter) + + filter_1 = {'category__in':['anish', 'singh']} + response = ~Q(**filter_1) + + assert constructed_expense_filter == response + assert constructed_expense_filter == response #custom-properties-number-is-equal