From 8a540f679c715f4065aae6cb697fb8e8e1ddaf7b Mon Sep 17 00:00:00 2001 From: Anish Kr Singh <116036738+anishfyle@users.noreply.github.com> Date: Tue, 9 Jul 2024 16:45:39 +0530 Subject: [PATCH] Intacct: Handle Split Expense (#522) * Intacct: Handle Split Expense * Split expense with tests * bump version --- .../migrations/0032_auto_20240703_1818.py | 24 + apps/fyle/models.py | 13 +- .../apis/export_settings/serializers.py | 4 +- requirements.txt | 2 +- .../032-mark-split-expense-grouping.sql | 5 + .../migration_fixtures/create_migration.sh | 6 + .../reset_db_fixtures/reset_db.sql | 21 +- tests/test_fyle/fixtures.py | 415 +++++++++++++++++- tests/test_fyle/test_models.py | 75 ++++ tests/test_fyle/test_task.py | 1 + tests/test_workspaces/fixtures.py | 1 + .../test_export_settings/fixtures.py | 6 +- 12 files changed, 558 insertions(+), 15 deletions(-) create mode 100644 apps/fyle/migrations/0032_auto_20240703_1818.py create mode 100644 scripts/sql/scripts/032-mark-split-expense-grouping.sql diff --git a/apps/fyle/migrations/0032_auto_20240703_1818.py b/apps/fyle/migrations/0032_auto_20240703_1818.py new file mode 100644 index 00000000..64f3cc2a --- /dev/null +++ b/apps/fyle/migrations/0032_auto_20240703_1818.py @@ -0,0 +1,24 @@ +# Generated by Django 3.2.14 on 2024-07-03 18:18 + +import apps.fyle.models +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fyle', '0031_expense_paid_on_fyle'), + ] + + operations = [ + migrations.AddField( + model_name='expense', + name='bank_transaction_id', + field=models.CharField(blank=True, help_text='Bank Transaction ID', max_length=255, null=True), + ), + migrations.AddField( + model_name='expensegroupsettings', + name='split_expense_grouping', + field=models.CharField(choices=[('SINGLE_LINE_ITEM', 'SINGLE_LINE_ITEM'), ('MULTIPLE_LINE_ITEM', 'MULTIPLE_LINE_ITEM')], default=apps.fyle.models.get_default_split_expense_grouping, help_text='specify line items for split expenses grouping', max_length=100), + ), + ] diff --git a/apps/fyle/models.py b/apps/fyle/models.py index 2a731845..dc443c0d 100644 --- a/apps/fyle/models.py +++ b/apps/fyle/models.py @@ -38,6 +38,9 @@ ('PAYMENT_PROCESSING', 'PAYMENT_PROCESSING') ) + +SPLIT_EXPENSE_GROUPING = (('SINGLE_LINE_ITEM', 'SINGLE_LINE_ITEM'), ('MULTIPLE_LINE_ITEM', 'MULTIPLE_LINE_ITEM')) + EXPENSE_FILTER_RANK = ( (1, 1), (2, 2) @@ -89,6 +92,10 @@ def get_default_expense_state(): def get_default_ccc_expense_state(): return 'PAID' +def get_default_split_expense_grouping(): + return 'MULTIPLE_LINE_ITEM' + + class Expense(models.Model): """ Expense @@ -117,6 +124,7 @@ class Expense(models.Model): cost_center = models.CharField(max_length=255, null=True, blank=True, help_text='Fyle Expense Cost Center') purpose = models.TextField(null=True, blank=True, help_text='Purpose') report_id = models.CharField(max_length=255, help_text='Report ID') + bank_transaction_id = models.CharField(max_length=255, null=True, blank=True, help_text='Bank Transaction ID') spent_at = models.DateTimeField(null=True, help_text='Expense spent at') approved_at = models.DateTimeField(null=True, help_text='Expense approved at') posted_at = models.DateTimeField(null=True, help_text='Date when the money is taken from the bank') @@ -179,6 +187,7 @@ def create_expense_objects(expenses: List[Dict], workspace_id: int): 'purpose': expense['purpose'], 'report_id': expense['report_id'], 'report_title': expense['report_title'], + 'bank_transaction_id': expense['bank_transaction_id'], 'spent_at': expense['spent_at'], 'approved_at': expense['approved_at'], 'posted_at': expense['posted_at'], @@ -221,6 +230,7 @@ class ExpenseGroupSettings(models.Model): choices=CCC_EXPENSE_STATE, help_text='state at which the ccc expenses are fetched (APPROVED/PAID)', null=True) reimbursable_export_date_type = models.CharField(max_length=100, default='current_date', help_text='Export Date') ccc_export_date_type = models.CharField(max_length=100, default='current_date', help_text='CCC Export Date') + split_expense_grouping = models.CharField(max_length=100, default=get_default_split_expense_grouping, choices=SPLIT_EXPENSE_GROUPING, help_text='specify line items for split expenses grouping') workspace = models.OneToOneField( Workspace, on_delete=models.PROTECT, help_text='To which workspace this expense group setting belongs to', @@ -321,7 +331,8 @@ def update_expense_group_settings(expense_group_settings: Dict, workspace_id: in 'expense_state': expense_group_settings['expense_state'], 'ccc_expense_state': expense_group_settings['ccc_expense_state'], 'reimbursable_export_date_type': expense_group_settings['reimbursable_export_date_type'], - 'ccc_export_date_type': expense_group_settings['ccc_export_date_type'] + 'ccc_export_date_type': expense_group_settings['ccc_export_date_type'], + 'split_expense_grouping': expense_group_settings['split_expense_grouping'] } ) diff --git a/apps/workspaces/apis/export_settings/serializers.py b/apps/workspaces/apis/export_settings/serializers.py index 0cf787f2..e02c692c 100644 --- a/apps/workspaces/apis/export_settings/serializers.py +++ b/apps/workspaces/apis/export_settings/serializers.py @@ -103,6 +103,7 @@ class ExpenseGroupSettingsSerializer(serializers.ModelSerializer): corporate_credit_card_expense_group_fields = serializers.ListField(allow_null=True, required=False) ccc_export_date_type = serializers.CharField(allow_null=True, allow_blank=True, required=False) ccc_expense_state = serializers.CharField(allow_null=True, allow_blank=True, required=False) + split_expense_grouping = serializers.CharField(allow_null=False, allow_blank=False, required=True) class Meta: model = ExpenseGroupSettings @@ -112,7 +113,8 @@ class Meta: 'expense_state', 'corporate_credit_card_expense_group_fields', 'ccc_export_date_type', - 'ccc_expense_state' + 'ccc_expense_state', + 'split_expense_grouping' ] diff --git a/requirements.txt b/requirements.txt index 69df6786..5fef35e1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -12,7 +12,7 @@ django-sendgrid-v5==1.2.0 future==0.18.2 fyle==0.37.0 fyle-accounting-mappings==1.32.1 -fyle-integrations-platform-connector==1.38.1 +fyle-integrations-platform-connector==1.38.3 fyle-rest-auth==1.7.2 gevent==23.9.1 gunicorn==20.1.0 diff --git a/scripts/sql/scripts/032-mark-split-expense-grouping.sql b/scripts/sql/scripts/032-mark-split-expense-grouping.sql new file mode 100644 index 00000000..90ad5741 --- /dev/null +++ b/scripts/sql/scripts/032-mark-split-expense-grouping.sql @@ -0,0 +1,5 @@ +rollback; +begin; + +UPDATE expense_group_settings +SET split_expense_grouping = 'SINGLE_LINE_ITEM'; \ No newline at end of file diff --git a/tests/sql_fixtures/migration_fixtures/create_migration.sh b/tests/sql_fixtures/migration_fixtures/create_migration.sh index a7b8545e..800fddbe 100644 --- a/tests/sql_fixtures/migration_fixtures/create_migration.sh +++ b/tests/sql_fixtures/migration_fixtures/create_migration.sh @@ -1,5 +1,11 @@ #!/bin/bash +echo "Current working directory: $(pwd)" +echo "Checking if file exists:" +ls -l ../../../scripts/sql/scripts/032-mark-split-expense-grouping.sql + +echo "Contents of scripts directory:" +ls -l ../../../scripts/sql/scripts/ # Setting value for DB Host export DB_HOST=db diff --git a/tests/sql_fixtures/reset_db_fixtures/reset_db.sql b/tests/sql_fixtures/reset_db_fixtures/reset_db.sql index f3621252..acd2654e 100644 --- a/tests/sql_fixtures/reset_db_fixtures/reset_db.sql +++ b/tests/sql_fixtures/reset_db_fixtures/reset_db.sql @@ -990,7 +990,8 @@ CREATE TABLE public.expense_group_settings ( updated_at timestamp with time zone NOT NULL, workspace_id integer NOT NULL, ccc_export_date_type character varying(100) NOT NULL, - ccc_expense_state character varying(100) + ccc_expense_state character varying(100), + split_expense_grouping character varying(100) NOT NULL ); @@ -1154,7 +1155,8 @@ CREATE TABLE public.expenses ( accounting_export_summary jsonb NOT NULL, previous_export_state character varying(255), workspace_id integer, - paid_on_fyle boolean NOT NULL + paid_on_fyle boolean NOT NULL, + bank_transaction_id character varying(255) ); @@ -4108,6 +4110,7 @@ COPY public.django_migrations (id, app, name, applied) FROM stdin; 182 tasks 0009_tasklog_supdoc_id 2024-05-20 09:36:04.874867+00 183 fyle 0031_expense_paid_on_fyle 2024-06-05 16:26:11.775475+00 184 workspaces 0034_configuration_is_journal_credit_billable 2024-06-19 07:16:22.418147+00 +185 fyle 0032_auto_20240703_1818 2024-07-03 18:29:14.061756+00 \. @@ -7497,8 +7500,8 @@ COPY public.expense_filters (id, condition, operator, "values", rank, join_by, i -- Data for Name: expense_group_settings; Type: TABLE DATA; Schema: public; Owner: postgres -- -COPY public.expense_group_settings (id, reimbursable_expense_group_fields, corporate_credit_card_expense_group_fields, expense_state, reimbursable_export_date_type, created_at, updated_at, workspace_id, ccc_export_date_type, ccc_expense_state) FROM stdin; -1 {employee_email,report_id,claim_number,fund_source} {employee_email,report_id,expense_id,claim_number,fund_source} PAYMENT_PROCESSING current_date 2022-09-20 08:38:03.358472+00 2022-09-20 08:39:32.022875+00 1 spent_at PAID +COPY public.expense_group_settings (id, reimbursable_expense_group_fields, corporate_credit_card_expense_group_fields, expense_state, reimbursable_export_date_type, created_at, updated_at, workspace_id, ccc_export_date_type, ccc_expense_state, split_expense_grouping) FROM stdin; +1 {employee_email,report_id,claim_number,fund_source} {employee_email,report_id,expense_id,claim_number,fund_source} PAYMENT_PROCESSING current_date 2022-09-20 08:38:03.358472+00 2022-09-20 08:39:32.022875+00 1 spent_at PAID MULTIPLE_LINE_ITEM \. @@ -7544,10 +7547,10 @@ COPY public.expense_reports (id, employee_id, description, supdoc_id, created_at -- Data for Name: expenses; Type: TABLE DATA; Schema: public; Owner: postgres -- -COPY public.expenses (id, employee_email, category, sub_category, project, expense_id, expense_number, claim_number, amount, currency, foreign_amount, foreign_currency, settlement_id, reimbursable, state, vendor, cost_center, purpose, report_id, spent_at, approved_at, expense_created_at, expense_updated_at, created_at, updated_at, fund_source, custom_properties, verified_at, billable, paid_on_sage_intacct, org_id, tax_amount, tax_group_id, file_ids, payment_number, corporate_card_id, is_skipped, report_title, posted_at, employee_name, accounting_export_summary, previous_export_state, workspace_id, paid_on_fyle) FROM stdin; -1 ashwin.t@fyle.in Food \N Aaron Abbott txR9dyrqr1Jn E/2022/09/T/21 C/2022/09/R/21 21 USD \N \N setqwcKcC9q1k t PAYMENT_PROCESSING Ashwin Marketing \N rpEZGqVCyWxQ 2022-09-20 17:00:00+00 2022-09-19 19:54:36.96+00 2022-09-19 19:54:15.870239+00 2022-09-19 19:55:58.641995+00 2022-09-20 08:48:21.737374+00 2022-09-20 08:48:21.737392+00 PERSONAL {"Team": "", "Class": "", "Klass": "", "Location": "", "Team Copy": "", "Tax Groups": "", "Departments": "", "Team 2 Postman": "", "User Dimension": "", "Location Entity": "", "Operating System": "", "System Operating": "", "User Dimension Copy": "", "Custom Expense Field": null} \N \N f or79Cob97KSh \N \N {} P/2022/09/R/18 \N f \N \N \N {} \N \N f -2 ashwin.t@fyle.in Food \N Aaron Abbott txCqLqsEnAjf E/2022/09/T/22 C/2022/09/R/22 11 USD \N \N setzhjuqQ6Pl5 f PAYMENT_PROCESSING Ashwin Marketing \N rpSTYO8AfUVA 2022-09-20 17:00:00+00 2022-09-20 08:50:48.428+00 2022-09-20 08:50:27.570399+00 2022-09-20 08:51:13.891379+00 2022-09-20 08:51:27.566571+00 2022-09-20 08:51:27.566598+00 CCC {"Team": "", "Class": "", "Klass": "", "Location": "", "Team Copy": "", "Tax Groups": "", "Departments": "", "Team 2 Postman": "", "User Dimension": "", "Location Entity": "", "Operating System": "", "System Operating": "", "User Dimension Copy": "", "Custom Expense Field": null} \N t f or79Cob97KSh 2.41 tggu76WXIdjY {} P/2022/09/R/19 \N f \N \N \N {} \N \N f -3 ashwin.t@fyle.in Taxi \N Aaron Abbott txTHfEPWOEOp E/2022/09/T/23 C/2022/09/R/23 22 USD \N \N set0SnAq66Zbq f PAYMENT_PROCESSING Ashwin Marketing \N rpBf5ibqUT6B 2022-09-20 17:00:00+00 2022-09-20 08:56:09.337+00 2022-09-20 08:55:53.246893+00 2022-09-20 08:56:40.795304+00 2022-09-20 08:56:50.117313+00 2022-09-20 08:56:50.117349+00 CCC {"Team": "", "Class": "", "Klass": "", "Location": "", "Team Copy": "", "Tax Groups": "", "Departments": "", "Team 2 Postman": "", "User Dimension": "", "Location Entity": "", "Operating System": "", "System Operating": "", "User Dimension Copy": "", "Custom Expense Field": null} \N \N f or79Cob97KSh 4.81 tggu76WXIdjY {} P/2022/09/R/20 \N f \N \N \N {} \N \N f +COPY public.expenses (id, employee_email, category, sub_category, project, expense_id, expense_number, claim_number, amount, currency, foreign_amount, foreign_currency, settlement_id, reimbursable, state, vendor, cost_center, purpose, report_id, spent_at, approved_at, expense_created_at, expense_updated_at, created_at, updated_at, fund_source, custom_properties, verified_at, billable, paid_on_sage_intacct, org_id, tax_amount, tax_group_id, file_ids, payment_number, corporate_card_id, is_skipped, report_title, posted_at, employee_name, accounting_export_summary, previous_export_state, workspace_id, paid_on_fyle, bank_transaction_id) FROM stdin; +1 ashwin.t@fyle.in Food \N Aaron Abbott txR9dyrqr1Jn E/2022/09/T/21 C/2022/09/R/21 21 USD \N \N setqwcKcC9q1k t PAYMENT_PROCESSING Ashwin Marketing \N rpEZGqVCyWxQ 2022-09-20 17:00:00+00 2022-09-19 19:54:36.96+00 2022-09-19 19:54:15.870239+00 2022-09-19 19:55:58.641995+00 2022-09-20 08:48:21.737374+00 2022-09-20 08:48:21.737392+00 PERSONAL {"Team": "", "Class": "", "Klass": "", "Location": "", "Team Copy": "", "Tax Groups": "", "Departments": "", "Team 2 Postman": "", "User Dimension": "", "Location Entity": "", "Operating System": "", "System Operating": "", "User Dimension Copy": "", "Custom Expense Field": null} \N \N f or79Cob97KSh \N \N {} P/2022/09/R/18 \N f \N \N \N {} \N \N f \N +2 ashwin.t@fyle.in Food \N Aaron Abbott txCqLqsEnAjf E/2022/09/T/22 C/2022/09/R/22 11 USD \N \N setzhjuqQ6Pl5 f PAYMENT_PROCESSING Ashwin Marketing \N rpSTYO8AfUVA 2022-09-20 17:00:00+00 2022-09-20 08:50:48.428+00 2022-09-20 08:50:27.570399+00 2022-09-20 08:51:13.891379+00 2022-09-20 08:51:27.566571+00 2022-09-20 08:51:27.566598+00 CCC {"Team": "", "Class": "", "Klass": "", "Location": "", "Team Copy": "", "Tax Groups": "", "Departments": "", "Team 2 Postman": "", "User Dimension": "", "Location Entity": "", "Operating System": "", "System Operating": "", "User Dimension Copy": "", "Custom Expense Field": null} \N t f or79Cob97KSh 2.41 tggu76WXIdjY {} P/2022/09/R/19 \N f \N \N \N {} \N \N f \N +3 ashwin.t@fyle.in Taxi \N Aaron Abbott txTHfEPWOEOp E/2022/09/T/23 C/2022/09/R/23 22 USD \N \N set0SnAq66Zbq f PAYMENT_PROCESSING Ashwin Marketing \N rpBf5ibqUT6B 2022-09-20 17:00:00+00 2022-09-20 08:56:09.337+00 2022-09-20 08:55:53.246893+00 2022-09-20 08:56:40.795304+00 2022-09-20 08:56:50.117313+00 2022-09-20 08:56:50.117349+00 CCC {"Team": "", "Class": "", "Klass": "", "Location": "", "Team Copy": "", "Tax Groups": "", "Departments": "", "Team 2 Postman": "", "User Dimension": "", "Location Entity": "", "Operating System": "", "System Operating": "", "User Dimension Copy": "", "Custom Expense Field": null} \N \N f or79Cob97KSh 4.81 tggu76WXIdjY {} P/2022/09/R/20 \N f \N \N \N {} \N \N f \N \. @@ -8115,7 +8118,7 @@ SELECT pg_catalog.setval('public.django_content_type_id_seq', 50, true); -- Name: django_migrations_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres -- -SELECT pg_catalog.setval('public.django_migrations_id_seq', 184, true); +SELECT pg_catalog.setval('public.django_migrations_id_seq', 185, true); -- diff --git a/tests/test_fyle/fixtures.py b/tests/test_fyle/fixtures.py index 17670ea8..fefe960f 100644 --- a/tests/test_fyle/fixtures.py +++ b/tests/test_fyle/fixtures.py @@ -242,6 +242,7 @@ 'vendor': None, 'cost_center': 'Administration', 'corporate_card_id': None, + 'bank_transaction_id': 'btxnParmar', 'purpose': None, 'report_id': 'rpN41rGGnxNI', 'billable': False, @@ -299,6 +300,7 @@ 'vendor': None, 'cost_center': None, 'corporate_card_id': None, + 'bank_transaction_id': 'Anish', 'purpose': None, 'report_id': 'rpqaDywYdbbw', 'file_ids': [], @@ -343,6 +345,7 @@ 'vendor': None, 'cost_center': None, 'corporate_card_id': None, + 'bank_transaction_id': 'Anish', 'purpose': None, 'report_id': 'rpqaDywYdbbw', 'file_ids': [], @@ -387,6 +390,7 @@ 'vendor': None, 'cost_center': None, 'corporate_card_id': None, + 'bank_transaction_id': 'Anish', 'purpose': None, 'report_id': 'rpqaDywYdbbr', 'file_ids': [], @@ -429,6 +433,7 @@ 'vendor': None, 'cost_center': None, 'corporate_card_id': None, + 'bank_transaction_id': 'Anish', 'purpose': None, 'report_id': 'rpqaDywYdbbr', 'file_ids': [], @@ -473,6 +478,7 @@ 'vendor': None, 'cost_center': None, 'corporate_card_id': None, + 'bank_transaction_id': 'Anish', 'purpose': None, 'report_id': 'rpqaDywYdbbr', 'file_ids': [], @@ -515,6 +521,7 @@ 'vendor': None, 'cost_center': None, 'corporate_card_id': None, + 'bank_transaction_id': 'Anish', 'purpose': None, 'report_id': 'rpqaDywYdbbr', 'file_ids': [], @@ -531,6 +538,408 @@ }, }, ], + 'ccc_expenses_split_no_bank_transaction_id': [ + { + 'id': '24008', + 'employee_email': 'admin1@fyleforbamboohr.com', + 'employee_name': 'Theresa Brown', + 'report_title': 'anish june 1', + 'category': 'Taxi', + 'sub_category': None, + 'project': None, + 'project_id': None, + 'expense_number': 'E/2024/06/T/1', + 'org_id': 'ordcXCcYSOTd', + 'claim_number': 'C/2024/06/R/1', + 'amount': 16.74, + 'tax_amount': None, + 'tax_group_id': None, + 'settled_at': None, + 'currency': 'USD', + 'foreign_amount': None, + 'foreign_currency': None, + 'settlement_id': 'set73HV1I8xvm', + 'reimbursable': False, + 'billable': None, + 'state': 'APPROVED', + 'vendor': 'Lyft', + 'cost_center': None, + 'corporate_card_id': 'baccOhXVSIlP7S', + 'bank_transaction_id': '', + 'purpose': None, + 'report_id': 'rp6lAwelLh54', + 'file_ids': [], + 'spent_at': '2024-06-05T00:00:00+00:00', + 'posted_at': None, + 'approved_at': '2024-06-05T12:35:28.453+00:00', + 'expense_created_at': '2024-06-05T12:34:09.350864+00:00', + 'expense_updated_at': '2024-06-10T11:45:43.338229+00:00', + 'source_account_type': 'PERSONAL_CORPORATE_CREDIT_CARD_ACCOUNT', + 'verified_at': None, + 'custom_properties': {}, + 'payment_number': 'P/2024/06/T/P/2024/06/R/1', + 'is_skipped': False, + 'accounting_export_summary': {}, + 'workspace_id': 1, + 'previous_export_state': None, + 'paid_on_fyle': False, + 'paid_on_qbo': False, + 'created_at': '2024-06-18T19:12:17.003409+00:00', + 'updated_at': '2024-06-18T19:12:17.003421+00:00' + }, + { + 'id': '24009', + 'employee_email': 'admin1@fyleforbamboohr.com', + 'employee_name': 'Theresa Brown', + 'report_title': 'anish june 2', + 'category': 'Taxi', + 'sub_category': None, + 'project': 'Project 2', + 'project_id': None, + 'expense_number': 'E/2024/06/T/2', + 'org_id': 'ordcXCcYSOTd', + 'claim_number': 'C/2024/06/R/1', + 'amount': 100, + 'tax_amount': None, + 'tax_group_id': None, + 'settled_at': None, + 'currency': 'USD', + 'foreign_amount': None, + 'foreign_currency': None, + 'settlement_id': 'set73HV1I8xvm', + 'reimbursable': False, + 'billable': None, + 'state': 'APPROVED', + 'vendor': None, + 'cost_center': 'F & A', + 'corporate_card_id': None, + 'bank_transaction_id': 'Anish', + 'purpose': None, + 'report_id': 'rp6lAwelLh54', + 'file_ids': [], + 'spent_at': '2024-06-05T00:00:00+00:00', + 'posted_at': None, + 'approved_at': '2024-06-05T12:35:28.453+00:00', + 'expense_created_at': '2024-06-05T12:34:41.770252+00:00', + 'expense_updated_at': '2024-06-10T11:45:09.305064+00:00', + 'source_account_type': 'PERSONAL_CORPORATE_CREDIT_CARD_ACCOUNT', + 'verified_at': None, + 'custom_properties': { + 'Ashwin test 1': None, + 'Custom Expense Field': None, + }, + 'payment_number': 'P/2024/06/T/P/2024/06/R/1', + 'is_skipped': False, + 'accounting_export_summary': {}, + 'workspace_id': 1, + 'previous_export_state': None, + 'paid_on_fyle': False, + 'paid_on_qbo': False, + 'created_at': '2024-06-18T19:12:17.020617+00:00', + 'updated_at': '2024-06-18T19:12:17.020627+00:00' + } + ], + 'ccc_expenses_split_same_bank_transaction_id': [ + { + 'id': '24008', + 'employee_email': 'admin1@fyleforbamboohr.com', + 'employee_name': 'Theresa Brown', + 'report_title': '#1: Jun 2024', + 'category': 'Taxi', + 'sub_category': None, + 'project': None, + 'project_id': None, + 'expense_number': 'E/2024/06/T/1', + 'org_id': 'ordcXCcYSOTd', + 'claim_number': 'C/2024/06/R/1', + 'amount': 16.74, + 'tax_amount': None, + 'tax_group_id': None, + 'settled_at': None, + 'currency': 'USD', + 'foreign_amount': None, + 'foreign_currency': None, + 'settlement_id': 'set73HV1I8xvm', + 'reimbursable': False, + 'billable': None, + 'state': 'APPROVED', + 'vendor': 'Lyft', + 'cost_center': None, + 'corporate_card_id': 'baccOhXVSIlP7S', + 'purpose': None, + 'report_id': 'rp6lAwelLh54', + 'file_ids': [], + 'spent_at': '2024-06-05T00:00:00+00:00', + 'posted_at': None, + 'approved_at': '2024-06-05T12:35:28.453+00:00', + 'expense_created_at': '2024-06-05T12:34:09.350864+00:00', + 'expense_updated_at': '2024-06-10T11:45:43.338229+00:00', + 'source_account_type': 'PERSONAL_CORPORATE_CREDIT_CARD_ACCOUNT', + 'verified_at': None, + 'custom_properties': {}, + 'payment_number': 'P/2024/06/T/P/2024/06/R/1', + 'is_skipped': False, + 'accounting_export_summary': {}, + 'workspace_id': 1, + 'previous_export_state': None, + 'paid_on_fyle': False, + 'paid_on_qbo': False, + 'created_at': '2024-06-18T19:12:17.003409+00:00', + 'updated_at': '2024-06-18T19:12:17.003421+00:00', + 'bank_transaction_id': 'anish' + }, + { + 'id': '24009', + 'employee_email': 'admin1@fyleforbamboohr.com', + 'employee_name': 'Theresa Brown', + 'report_title': '#1: Jun 2024', + 'category': 'Taxi', + 'sub_category': None, + 'project': 'Project 2', + 'project_id': None, + 'expense_number': 'E/2024/06/T/2', + 'org_id': 'ordcXCcYSOTd', + 'claim_number': 'C/2024/06/R/1', + 'amount': 100, + 'tax_amount': None, + 'tax_group_id': None, + 'settled_at': None, + 'currency': 'USD', + 'foreign_amount': None, + 'foreign_currency': None, + 'settlement_id': 'set73HV1I8xvm', + 'reimbursable': False, + 'billable': None, + 'state': 'APPROVED', + 'vendor': None, + 'cost_center': 'F & A', + 'corporate_card_id': None, + 'purpose': None, + 'report_id': 'rp6lAwelLh54', + 'file_ids': [], + 'spent_at': '2024-06-05T00:00:00+00:00', + 'posted_at': None, + 'approved_at': '2024-06-05T12:35:28.453+00:00', + 'expense_created_at': '2024-06-05T12:34:41.770252+00:00', + 'expense_updated_at': '2024-06-10T11:45:09.305064+00:00', + 'source_account_type': 'PERSONAL_CORPORATE_CREDIT_CARD_ACCOUNT', + 'verified_at': None, + 'custom_properties': { + 'Ashwin test 1': None, + 'Custom Expense Field': None, + }, + 'payment_number': 'P/2024/06/T/P/2024/06/R/1', + 'is_skipped': False, + 'accounting_export_summary': {}, + 'workspace_id': 1, + 'previous_export_state': None, + 'paid_on_fyle': False, + 'paid_on_qbo': False, + 'created_at': '2024-06-18T19:12:17.020617+00:00', + 'updated_at': '2024-06-18T19:12:17.020627+00:00', + 'bank_transaction_id': 'anish' + } + ], + 'ccc_expenses_split_diff_bank_transaction_id': [ + { + 'id': '24001', + 'employee_email': 'admin11@fyleforbamboohr.com', + 'employee_name': 'Theresa Brown', + 'report_title': '#1: Jul 2024', + 'category': 'Taxi', + 'sub_category': None, + 'project': None, + 'project_id': None, + 'expense_number': 'E/2024/06/T/12', + 'org_id': 'ordcXCcYSOTd', + 'claim_number': 'C/2024/06/R/12', + 'amount': 16.74, + 'tax_amount': None, + 'tax_group_id': None, + 'settled_at': None, + 'currency': 'USD', + 'foreign_amount': None, + 'foreign_currency': None, + 'settlement_id': 'set73HV1I8xvm', + 'reimbursable': False, + 'billable': None, + 'state': 'APPROVED', + 'vendor': 'Lyft', + 'cost_center': None, + 'corporate_card_id': 'baccOhXVSIlP7S', + 'purpose': None, + 'report_id': 'rp6lAwelLh54', + 'file_ids': [], + 'spent_at': '2024-06-05T00:00:00+00:00', + 'posted_at': None, + 'approved_at': '2024-06-05T12:35:28.453+00:00', + 'expense_created_at': '2024-06-05T12:34:09.350864+00:00', + 'expense_updated_at': '2024-06-10T11:45:43.338229+00:00', + 'source_account_type': 'PERSONAL_CORPORATE_CREDIT_CARD_ACCOUNT', + 'verified_at': None, + 'custom_properties': {}, + 'payment_number': 'P/2024/06/T/P/2024/06/R/1', + 'is_skipped': False, + 'accounting_export_summary': {}, + 'workspace_id': 1, + 'previous_export_state': None, + 'paid_on_fyle': False, + 'paid_on_qbo': False, + 'created_at': '2024-06-18T19:12:17.003409+00:00', + 'updated_at': '2024-06-18T19:12:17.003421+00:00', + 'bank_transaction_id': 'Arkham' + }, + { + 'id': '24004', + 'employee_email': 'admin21@fyleforbamboohr.com', + 'employee_name': 'Theresa Brown', + 'report_title': '#1: Aug 2024', + 'category': 'Taxi', + 'sub_category': None, + 'project': 'Project 2', + 'project_id': None, + 'expense_number': 'E/2024/06/T/23', + 'org_id': 'ordcXCcYSOTd', + 'claim_number': 'C/2024/06/R/14', + 'amount': 100, + 'tax_amount': None, + 'tax_group_id': None, + 'settled_at': None, + 'currency': 'USD', + 'foreign_amount': None, + 'foreign_currency': None, + 'settlement_id': 'set73HV1I8xvm', + 'reimbursable': False, + 'billable': None, + 'state': 'APPROVED', + 'vendor': None, + 'cost_center': 'F & A', + 'corporate_card_id': None, + 'purpose': None, + 'report_id': 'rp6lAwelLh54', + 'file_ids': [], + 'spent_at': '2024-06-05T00:00:00+00:00', + 'posted_at': None, + 'approved_at': '2024-06-05T12:35:28.453+00:00', + 'expense_created_at': '2024-06-05T12:34:41.770252+00:00', + 'expense_updated_at': '2024-06-10T11:45:09.305064+00:00', + 'source_account_type': 'PERSONAL_CORPORATE_CREDIT_CARD_ACCOUNT', + 'verified_at': None, + 'custom_properties': { + 'Ashwin test 1': None, + 'Custom Expense Field': None, + }, + 'payment_number': 'P/2024/06/T/P/2024/06/R/1', + 'is_skipped': False, + 'accounting_export_summary': {}, + 'workspace_id': 1, + 'previous_export_state': None, + 'paid_on_fyle': False, + 'paid_on_qbo': False, + 'created_at': '2024-06-18T19:12:17.020617+00:00', + 'updated_at': '2024-06-18T19:12:17.020627+00:00', + 'bank_transaction_id': 'Arkham' + }, + { + 'id': '24008', + 'employee_email': 'admin1@fyleforbamboohr.com', + 'employee_name': 'Theresa Brown', + 'report_title': '#1: Jun 2024', + 'category': 'Taxi', + 'sub_category': None, + 'project': None, + 'project_id': None, + 'expense_number': 'E/2024/06/T/1', + 'org_id': 'ordcXCcYSOTd', + 'claim_number': 'C/2024/06/R/1', + 'amount': 16.74, + 'tax_amount': None, + 'tax_group_id': None, + 'settled_at': None, + 'currency': 'USD', + 'foreign_amount': None, + 'foreign_currency': None, + 'settlement_id': 'set73HV1I8xvm', + 'reimbursable': False, + 'billable': None, + 'state': 'APPROVED', + 'vendor': 'Lyft', + 'cost_center': None, + 'corporate_card_id': 'baccOhXVSIlP7S', + 'purpose': None, + 'report_id': 'rp6lAwelLh54', + 'file_ids': [], + 'spent_at': '2024-06-05T00:00:00+00:00', + 'posted_at': None, + 'approved_at': '2024-06-05T12:35:28.453+00:00', + 'expense_created_at': '2024-06-05T12:34:09.350864+00:00', + 'expense_updated_at': '2024-06-10T11:45:43.338229+00:00', + 'source_account_type': 'PERSONAL_CORPORATE_CREDIT_CARD_ACCOUNT', + 'verified_at': None, + 'custom_properties': {}, + 'payment_number': 'P/2024/06/T/P/2024/06/R/1', + 'is_skipped': False, + 'accounting_export_summary': {}, + 'workspace_id': 1, + 'previous_export_state': None, + 'paid_on_fyle': False, + 'paid_on_qbo': False, + 'created_at': '2024-06-18T19:12:17.003409+00:00', + 'updated_at': '2024-06-18T19:12:17.003421+00:00', + 'bank_transaction_id': 'Anish' + }, + { + 'id': '24009', + 'employee_email': 'admin1@fyleforbamboohr.com', + 'employee_name': 'Theresa Brown', + 'report_title': '#1: Jun 2024', + 'category': 'Taxi', + 'sub_category': None, + 'project': 'Project 2', + 'project_id': None, + 'expense_number': 'E/2024/06/T/23', + 'org_id': 'ordcXCcYSOTd', + 'claim_number': 'C/2024/06/R/16', + 'amount': 100, + 'tax_amount': None, + 'tax_group_id': None, + 'settled_at': None, + 'currency': 'USD', + 'foreign_amount': None, + 'foreign_currency': None, + 'settlement_id': 'set73HV1I8xvm', + 'reimbursable': False, + 'billable': None, + 'state': 'APPROVED', + 'vendor': None, + 'cost_center': 'F & A', + 'corporate_card_id': None, + 'purpose': None, + 'report_id': 'rp6lAwelLh54', + 'file_ids': [], + 'spent_at': '2024-06-05T00:00:00+00:00', + 'posted_at': None, + 'approved_at': '2024-06-05T12:35:28.453+00:00', + 'expense_created_at': '2024-06-05T12:34:41.770252+00:00', + 'expense_updated_at': '2024-06-10T11:45:09.305064+00:00', + 'source_account_type': 'PERSONAL_CORPORATE_CREDIT_CARD_ACCOUNT', + 'verified_at': None, + 'custom_properties': { + 'Ashwin test 1': None, + 'Custom Expense Field': None, + }, + 'payment_number': 'P/2024/06/T/P/2024/06/R/1', + 'is_skipped': False, + 'accounting_export_summary': {}, + 'workspace_id': 1, + 'previous_export_state': None, + 'paid_on_fyle': False, + 'paid_on_qbo': False, + 'created_at': '2024-06-18T19:12:17.020617+00:00', + 'updated_at': '2024-06-18T19:12:17.020627+00:00', + 'bank_transaction_id': 'Anish' + } + ], 'expense_group_id': { 'id': 1, 'fund_source': 'PERSONAL', @@ -570,6 +979,7 @@ 'reimbursable_export_date_type': 'current_date', 'ccc_export_date_type': 'current_date', "ccc_expense_state": "PAID", + "split_expense_grouping": 'SINGLE_LINE_ITEM', 'created_at': '2021-11-15T08:46:16.069944Z', 'updated_at': '2021-11-15T08:46:16.069986Z', 'workspace': 1 @@ -600,7 +1010,8 @@ 'expense_state': 'PAYMENT_PROCESSING', 'reimbursable_export_date_type': 'spent_at', 'ccc_export_date_type': 'spent_at', - 'ccc_expense_state': 'PAID' + 'ccc_expense_state': 'PAID', + "split_expense_grouping": 'SINGLE_LINE_ITEM' }, 'expense_fields_response': [ { @@ -1230,6 +1641,7 @@ 'vendor': None, 'cost_center': None, 'corporate_card_id': None, + 'bank_transaction_id': 'Anish', 'purpose': None, 'report_id': 'rpqaDywYdbbw12', 'file_ids': [], @@ -1271,6 +1683,7 @@ 'vendor': None, 'cost_center': None, 'corporate_card_id': None, + 'bank_transaction_id': 'Anish', 'purpose': None, 'report_id': 'rpvpLIPrP1EO12', 'file_ids': [], diff --git a/tests/test_fyle/test_models.py b/tests/test_fyle/test_models.py index 30aeadee..ef5ef9da 100644 --- a/tests/test_fyle/test_models.py +++ b/tests/test_fyle/test_models.py @@ -95,6 +95,81 @@ def test_create_expense_groups_by_report_id_fund_source(db): assert expense_groups.exported_at == None +def test_split_expenses_no_bank_transaction_id(db): + # Grouping of expenses with no bank transaction id + expenses = data['ccc_expenses_split_no_bank_transaction_id'] + configuration = Configuration.objects.get(workspace_id=1) + configuration.corporate_credit_card_expenses_object = 'CREDIT CARD PURCHASE' + configuration.save() + + expense_group_settings = ExpenseGroupSettings.objects.get(workspace_id=1) + expense_group_settings.ccc_export_date_type = 'last_spent_at' + expense_group_settings.split_expense_grouping = 'SINGLE_LINE_ITEM' + expense_group_settings.save() + + expense_objects = Expense.create_expense_objects(expenses, 1) + assert len(expense_objects) == 2 + + expense_groups = _group_expenses(expense_objects, ['expense_id', 'fund_source', 'employee_email', 'spent_at'], 4) + assert len(expense_groups) == 2 + + expense_group_settings.split_expense_grouping = 'MULTIPLE_LINE_ITEM' + expense_group_settings.save() + + expense_groups = _group_expenses(expense_objects, ['expense_id', 'fund_source', 'employee_email', 'spent_at'], 4) + assert len(expense_groups) == 2 + + +def test_split_expenses_same_bank_transaction_id(db): + # Grouping of expenses with same bank transaction id + expenses = data['ccc_expenses_split_same_bank_transaction_id'] + configuration = Configuration.objects.get(workspace_id=1) + configuration.corporate_credit_card_expenses_object = 'CREDIT CARD PURCHASE' + configuration.save() + + expense_group_settings = ExpenseGroupSettings.objects.get(workspace_id=1) + expense_group_settings.ccc_export_date_type = 'last_spent_at' + expense_group_settings.split_expense_grouping = 'SINGLE_LINE_ITEM' + expense_group_settings.save() + + expense_objects = Expense.create_expense_objects(expenses, 1) + assert len(expense_objects) == 2 + + expense_groups = _group_expenses(expense_objects, ['expense_id', 'fund_source', 'employee_email', 'spent_at'], 4) + assert len(expense_groups) == 2 + + expense_group_settings.split_expense_grouping = 'MULTIPLE_LINE_ITEM' + expense_group_settings.save() + + expense_groups = _group_expenses(expense_objects, ['expense_id', 'fund_source', 'employee_email', 'spent_at'], 4) + assert len(expense_groups) == 2 + + +def test_split_expenses_diff_bank_transaction_id(db): + # Grouping of expenses with different bank transaction id + expenses = data['ccc_expenses_split_diff_bank_transaction_id'] + configuration = Configuration.objects.get(workspace_id=1) + configuration.corporate_credit_card_expenses_object = 'CREDIT CARD PURCHASE' + configuration.save() + + expense_group_settings = ExpenseGroupSettings.objects.get(workspace_id=1) + expense_group_settings.ccc_export_date_type = 'last_spent_at' + expense_group_settings.split_expense_grouping = 'SINGLE_LINE_ITEM' + expense_group_settings.save() + + expense_objects = Expense.create_expense_objects(expenses, 1) + assert len(expense_objects) == 4 + + expense_groups = _group_expenses(expense_objects, ['expense_id', 'fund_source', 'employee_email', 'spent_at'], 4) + assert len(expense_groups) == 4 + + expense_group_settings.split_expense_grouping = 'MULTIPLE_LINE_ITEM' + expense_group_settings.save() + + expense_groups = _group_expenses(expense_objects, ['expense_id', 'fund_source', 'employee_email', 'spent_at'], 4) + assert len(expense_groups) == 4 + + def test_create_expense_groups_by_report_id_fund_source_test_1(db): """ Group By Report diff --git a/tests/test_fyle/test_task.py b/tests/test_fyle/test_task.py index 18e40f97..fc79bc2b 100644 --- a/tests/test_fyle/test_task.py +++ b/tests/test_fyle/test_task.py @@ -182,6 +182,7 @@ def test_post_accounting_export_summary(db, mocker): def test_update_non_exported_expenses(db, create_temp_workspace, mocker, api_client): expense = data['raw_expense'] + expense['bank_transaction_id'] = 'btxnanish' default_raw_expense = data['default_raw_expense'] org_id = expense['org_id'] payload = { diff --git a/tests/test_workspaces/fixtures.py b/tests/test_workspaces/fixtures.py index 504d3215..d0318d01 100644 --- a/tests/test_workspaces/fixtures.py +++ b/tests/test_workspaces/fixtures.py @@ -21,6 +21,7 @@ 'tax_amount':None, 'tax_group_id':None, 'settlement_id':'setDiksMn83K7', + 'bank_transaction_id': 'anish', 'reimbursable':True, 'billable':False, 'exported':False, diff --git a/tests/test_workspaces/test_apis/test_export_settings/fixtures.py b/tests/test_workspaces/test_apis/test_export_settings/fixtures.py index a20173d8..1d56680e 100644 --- a/tests/test_workspaces/test_apis/test_export_settings/fixtures.py +++ b/tests/test_workspaces/test_apis/test_export_settings/fixtures.py @@ -26,7 +26,8 @@ 'expense_id' ], 'ccc_export_date_type': 'spent_at', - 'ccc_expense_state': 'PAID' + 'ccc_expense_state': 'PAID', + 'split_expense_grouping': 'SINGLE_LINE_ITEM' }, 'general_mappings': { 'default_gl_account': { @@ -82,7 +83,8 @@ 'expense_id' ], 'ccc_export_date_type': 'spent_at', - 'ccc_expense_state': 'PAID' + 'ccc_expense_state': 'PAID', + 'split_expense_grouping': 'SINGLE_LINE_ITEM' }, 'general_mappings': { 'default_gl_account': {