From 96c7dc61b2be86148f89e8c94b247f627208b362 Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Mon, 20 Nov 2023 16:45:37 +0530 Subject: [PATCH 1/8] add employee name in expense and script to populate data --- .../0027_expensegroup_employee_name.py | 18 ++++++++++++ apps/fyle/models.py | 8 ++++- ...ee_name-in-expenses-and-expense_groups.sql | 29 +++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) create mode 100644 apps/fyle/migrations/0027_expensegroup_employee_name.py create mode 100644 scripts/sql/scripts/020-fill-employee_name-in-expenses-and-expense_groups.sql diff --git a/apps/fyle/migrations/0027_expensegroup_employee_name.py b/apps/fyle/migrations/0027_expensegroup_employee_name.py new file mode 100644 index 00000000..d8901f3d --- /dev/null +++ b/apps/fyle/migrations/0027_expensegroup_employee_name.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.14 on 2023-11-20 10:48 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fyle', '0026_auto_20231025_0913'), + ] + + operations = [ + migrations.AddField( + model_name='expensegroup', + name='employee_name', + field=models.CharField(help_text='Expense Group Employee Name', max_length=100, null=True), + ), + ] diff --git a/apps/fyle/models.py b/apps/fyle/models.py index fed23cc2..13ae25b2 100644 --- a/apps/fyle/models.py +++ b/apps/fyle/models.py @@ -325,6 +325,7 @@ class ExpenseGroup(models.Model): help_text='To which workspace this expense group belongs to') fund_source = models.CharField(max_length=255, help_text='Expense fund source') expenses = models.ManyToManyField(Expense, help_text="Expenses under this Expense Group") + employee_name = models.CharField(max_length=100, help_text='Expense Group Employee Name', null=True) description = JSONField(max_length=255, help_text='Description', null=True) response_logs = JSONField(help_text='Reponse log of the export', null=True) created_at = models.DateTimeField(auto_now_add=True, help_text='Created at') @@ -392,6 +393,10 @@ def create_expense_groups_by_report_id_fund_source(expense_objects: List[Expense if expense_group_settings.ccc_export_date_type == 'last_spent_at': expense_group['last_spent_at'] = Expense.objects.filter( id__in=expense_group['expense_ids']).order_by('-spent_at').first().spent_at + + employee_name = Expense.objects.filter( + id__in=expense_group['expense_ids'] + ).first().employee_name expense_ids = expense_group['expense_ids'] expense_group.pop('total') @@ -407,7 +412,8 @@ def create_expense_groups_by_report_id_fund_source(expense_objects: List[Expense expense_group_object = ExpenseGroup.objects.create( workspace_id=workspace_id, fund_source=expense_group['fund_source'], - description=expense_group + description=expense_group, + employee_name=employee_name ) expense_group_object.expenses.add(*expense_ids) diff --git a/scripts/sql/scripts/020-fill-employee_name-in-expenses-and-expense_groups.sql b/scripts/sql/scripts/020-fill-employee_name-in-expenses-and-expense_groups.sql new file mode 100644 index 00000000..21ee0b5b --- /dev/null +++ b/scripts/sql/scripts/020-fill-employee_name-in-expenses-and-expense_groups.sql @@ -0,0 +1,29 @@ +rollback; +begin; + +with ws as ( + select expense_attributes.detail->>'full_name' as expense_attributes_full_name, + expense_attributes.workspace_id as expense_attributes_workspace_id, + expense_attributes.value as expense_attribute_email + from expense_groups + inner join expense_attributes on expense_attributes.value = expense_groups.description->>'employee_email' + where expense_groups.workspace_id = expense_attributes.workspace_id +) + +update expense_groups +set employee_name = ws.expense_attributes_full_name +from ws +where expense_groups.description->>'employee_email' = ws.expense_attribute_email; + + +-- Run this in after running the above query. +with ex as ( + select expense_groups.employee_name as employee_name + from expense_groups + inner join expense_groups_expenses on expense_groups.id = expense_groups_expenses.expensegroup_id + inner join expenses on expense_groups_expenses.expense_id = expenses.id +) + +update expenses +set employee_name = ex.employee_name +from ex; \ No newline at end of file From 3a7f7f2d020a47372df69c4035707247185d47e2 Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Mon, 20 Nov 2023 16:56:06 +0530 Subject: [PATCH 2/8] test fixture changes --- .../reset_db_fixtures/reset_db.sql | 169 +++++++++++++++--- tests/test_fyle/fixtures.py | 1 + 2 files changed, 149 insertions(+), 21 deletions(-) diff --git a/tests/sql_fixtures/reset_db_fixtures/reset_db.sql b/tests/sql_fixtures/reset_db_fixtures/reset_db.sql index e00398b6..84857da5 100644 --- a/tests/sql_fixtures/reset_db_fixtures/reset_db.sql +++ b/tests/sql_fixtures/reset_db_fixtures/reset_db.sql @@ -2,8 +2,8 @@ -- PostgreSQL database dump -- --- Dumped from database version 15.4 (Debian 15.4-2.pgdg120+1) --- Dumped by pg_dump version 15.4 (Debian 15.4-2.pgdg120+1) +-- Dumped from database version 15.2 (Debian 15.2-1.pgdg110+1) +-- Dumped by pg_dump version 15.5 (Debian 15.5-1.pgdg120+1) SET statement_timeout = 0; SET lock_timeout = 0; @@ -747,6 +747,48 @@ ALTER TABLE public.employee_mappings_id_seq OWNER TO postgres; ALTER SEQUENCE public.employee_mappings_id_seq OWNED BY public.employee_mappings.id; +-- +-- Name: errors; Type: TABLE; Schema: public; Owner: postgres +-- + +CREATE TABLE public.errors ( + id integer NOT NULL, + type character varying(50) NOT NULL, + is_resolved boolean NOT NULL, + error_title character varying(255) NOT NULL, + error_detail text NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone NOT NULL, + expense_attribute_id integer, + expense_group_id integer, + workspace_id integer NOT NULL +); + + +ALTER TABLE public.errors OWNER TO postgres; + +-- +-- Name: errors_id_seq; Type: SEQUENCE; Schema: public; Owner: postgres +-- + +CREATE SEQUENCE public.errors_id_seq + AS integer + START WITH 1 + INCREMENT BY 1 + NO MINVALUE + NO MAXVALUE + CACHE 1; + + +ALTER TABLE public.errors_id_seq OWNER TO postgres; + +-- +-- Name: errors_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: postgres +-- + +ALTER SEQUENCE public.errors_id_seq OWNED BY public.errors.id; + + -- -- Name: expense_attributes; Type: TABLE; Schema: public; Owner: postgres -- @@ -884,7 +926,8 @@ CREATE TABLE public.expense_groups ( workspace_id integer NOT NULL, fund_source character varying(255) NOT NULL, exported_at timestamp with time zone, - response_logs jsonb + response_logs jsonb, + employee_name character varying(100) ); @@ -2034,6 +2077,13 @@ ALTER TABLE ONLY public.django_q_schedule ALTER COLUMN id SET DEFAULT nextval('p ALTER TABLE ONLY public.employee_mappings ALTER COLUMN id SET DEFAULT nextval('public.employee_mappings_id_seq'::regclass); +-- +-- Name: errors id; Type: DEFAULT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.errors ALTER COLUMN id SET DEFAULT nextval('public.errors_id_seq'::regclass); + + -- -- Name: expense_attributes id; Type: DEFAULT; Schema: public; Owner: postgres -- @@ -2410,6 +2460,10 @@ COPY public.auth_permission (id, name, content_type_id, codename) FROM stdin; 170 Can change expense field 43 change_expensefield 171 Can delete expense field 43 delete_expensefield 172 Can view expense field 43 view_expensefield +173 Can add error 44 add_error +174 Can change error 44 change_error +175 Can delete error 44 delete_error +176 Can view error 44 view_error \. @@ -7539,6 +7593,7 @@ COPY public.django_content_type (id, app_label, model) FROM stdin; 41 django_q ormq 42 fyle expensefilter 43 fyle_accounting_mappings expensefield +44 tasks error \. @@ -7717,6 +7772,9 @@ COPY public.django_migrations (id, app, name, applied) FROM stdin; 169 mappings 0010_auto_20231025_0915 2023-11-07 07:21:37.268291+00 170 mappings 0011_auto_20231107_0720 2023-11-07 07:21:37.285191+00 171 netsuite 0023_bill_department_id 2023-11-07 07:21:37.291269+00 +172 fyle 0027_expensegroup_employee_name 2023-11-20 11:19:47.476133+00 +173 workspaces 0036_auto_20231027_0709 2023-11-20 11:19:47.53547+00 +174 tasks 0009_error 2023-11-20 11:19:47.609035+00 \. @@ -7782,6 +7840,14 @@ COPY public.employee_mappings (id, created_at, updated_at, destination_card_acco \. +-- +-- Data for Name: errors; Type: TABLE DATA; Schema: public; Owner: postgres +-- + +COPY public.errors (id, type, is_resolved, error_title, error_detail, created_at, updated_at, expense_attribute_id, expense_group_id, workspace_id) FROM stdin; +\. + + -- -- Data for Name: expense_attributes; Type: TABLE DATA; Schema: public; Owner: postgres -- @@ -11298,13 +11364,13 @@ COPY public.expense_group_settings (id, reimbursable_expense_group_fields, corpo -- Data for Name: expense_groups; Type: TABLE DATA; Schema: public; Owner: postgres -- -COPY public.expense_groups (id, description, created_at, updated_at, workspace_id, fund_source, exported_at, response_logs) FROM stdin; -1 {"report_id": "rpuN3bgphxbK", "fund_source": "PERSONAL", "claim_number": "C/2021/11/R/5", "employee_email": "ashwin.t@fyle.in"} 2021-11-15 10:29:07.618062+00 2021-11-15 11:02:55.125634+00 1 PERSONAL \N \N -2 {"report_id": "rpHLA9Dfp9hN", "fund_source": "CCC", "claim_number": "C/2021/11/R/6", "employee_email": "ashwin.t@fyle.in"} 2021-11-15 13:12:12.275539+00 2021-11-15 13:27:27.538211+00 1 CCC \N \N -3 {"report_id": "rpu5W0LYrk6e", "fund_source": "PERSONAL", "claim_number": "C/2021/11/R/2", "employee_email": "ashwin.t@fyle.in"} 2021-11-16 04:25:49.206777+00 2021-11-16 04:25:49.206809+00 2 PERSONAL \N \N -4 {"spent_at": "2021-11-16", "report_id": "rprqDvARHUnv", "expense_id": "txMLGb6Xy8m8", "fund_source": "CCC", "claim_number": "C/2021/11/R/1", "employee_email": "ashwin.t@fyle.in"} 2021-11-16 04:25:49.226855+00 2021-11-16 04:25:49.226855+00 2 CCC \N \N -47 {"report_id": "rpXqCutQj85N", "fund_source": "PERSONAL", "claim_number": "C/2021/12/R/1", "employee_email": "admin1@fyleforintacct.in"} 2021-12-03 11:26:58.731339+00 2021-12-03 11:26:58.731398+00 49 PERSONAL \N \N -48 {"report_id": "rpXqCutQj85N", "expense_id": "txcKVVELn1Vl", "fund_source": "CCC", "claim_number": "C/2021/12/R/1", "employee_email": "admin1@fyleforintacct.in"} 2021-12-03 11:26:58.746214+00 2021-12-03 11:26:58.746248+00 49 CCC \N \N +COPY public.expense_groups (id, description, created_at, updated_at, workspace_id, fund_source, exported_at, response_logs, employee_name) FROM stdin; +1 {"report_id": "rpuN3bgphxbK", "fund_source": "PERSONAL", "claim_number": "C/2021/11/R/5", "employee_email": "ashwin.t@fyle.in"} 2021-11-15 10:29:07.618062+00 2021-11-15 11:02:55.125634+00 1 PERSONAL \N \N \N +2 {"report_id": "rpHLA9Dfp9hN", "fund_source": "CCC", "claim_number": "C/2021/11/R/6", "employee_email": "ashwin.t@fyle.in"} 2021-11-15 13:12:12.275539+00 2021-11-15 13:27:27.538211+00 1 CCC \N \N \N +3 {"report_id": "rpu5W0LYrk6e", "fund_source": "PERSONAL", "claim_number": "C/2021/11/R/2", "employee_email": "ashwin.t@fyle.in"} 2021-11-16 04:25:49.206777+00 2021-11-16 04:25:49.206809+00 2 PERSONAL \N \N \N +4 {"spent_at": "2021-11-16", "report_id": "rprqDvARHUnv", "expense_id": "txMLGb6Xy8m8", "fund_source": "CCC", "claim_number": "C/2021/11/R/1", "employee_email": "ashwin.t@fyle.in"} 2021-11-16 04:25:49.226855+00 2021-11-16 04:25:49.226855+00 2 CCC \N \N \N +47 {"report_id": "rpXqCutQj85N", "fund_source": "PERSONAL", "claim_number": "C/2021/12/R/1", "employee_email": "admin1@fyleforintacct.in"} 2021-12-03 11:26:58.731339+00 2021-12-03 11:26:58.731398+00 49 PERSONAL \N \N \N +48 {"report_id": "rpXqCutQj85N", "expense_id": "txcKVVELn1Vl", "fund_source": "CCC", "claim_number": "C/2021/12/R/1", "employee_email": "admin1@fyleforintacct.in"} 2021-12-03 11:26:58.746214+00 2021-12-03 11:26:58.746248+00 49 CCC \N \N \N \. @@ -11533,7 +11599,7 @@ SELECT pg_catalog.setval('public.auth_group_permissions_id_seq', 1, false); -- Name: auth_permission_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres -- -SELECT pg_catalog.setval('public.auth_permission_id_seq', 172, true); +SELECT pg_catalog.setval('public.auth_permission_id_seq', 176, true); -- @@ -11589,14 +11655,14 @@ SELECT pg_catalog.setval('public.django_admin_log_id_seq', 1, false); -- Name: django_content_type_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres -- -SELECT pg_catalog.setval('public.django_content_type_id_seq', 43, true); +SELECT pg_catalog.setval('public.django_content_type_id_seq', 44, true); -- -- Name: django_migrations_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres -- -SELECT pg_catalog.setval('public.django_migrations_id_seq', 171, true); +SELECT pg_catalog.setval('public.django_migrations_id_seq', 174, true); -- @@ -11620,6 +11686,13 @@ SELECT pg_catalog.setval('public.django_q_schedule_id_seq', 50, true); SELECT pg_catalog.setval('public.employee_mappings_id_seq', 3, true); +-- +-- Name: errors_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres +-- + +SELECT pg_catalog.setval('public.errors_id_seq', 1, false); + + -- -- Name: expense_fields_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres -- @@ -12064,6 +12137,22 @@ ALTER TABLE ONLY public.employee_mappings ADD CONSTRAINT employee_mappings_pkey PRIMARY KEY (id); +-- +-- Name: errors errors_expense_attribute_id_key; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.errors + ADD CONSTRAINT errors_expense_attribute_id_key UNIQUE (expense_attribute_id); + + +-- +-- Name: errors errors_pkey; Type: CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.errors + ADD CONSTRAINT errors_pkey PRIMARY KEY (id); + + -- -- Name: expense_attributes expense_attributes_value_attribute_type_wor_a06aa6b3_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres -- @@ -12657,6 +12746,20 @@ CREATE INDEX employee_mappings_source_employee_id_dd9948ba ON public.employee_ma CREATE INDEX employee_mappings_workspace_id_4a25f8c9 ON public.employee_mappings USING btree (workspace_id); +-- +-- Name: errors_expense_group_id_86fafc8b; Type: INDEX; Schema: public; Owner: postgres +-- + +CREATE INDEX errors_expense_group_id_86fafc8b ON public.errors USING btree (expense_group_id); + + +-- +-- Name: errors_workspace_id_a33dd61b; Type: INDEX; Schema: public; Owner: postgres +-- + +CREATE INDEX errors_workspace_id_a33dd61b ON public.errors USING btree (workspace_id); + + -- -- Name: expense_fields_workspace_id_b60af18c; Type: INDEX; Schema: public; Owner: postgres -- @@ -13042,6 +13145,30 @@ ALTER TABLE ONLY public.employee_mappings ADD CONSTRAINT employee_mappings_workspace_id_4a25f8c9_fk_workspaces_id FOREIGN KEY (workspace_id) REFERENCES public.workspaces(id) DEFERRABLE INITIALLY DEFERRED; +-- +-- Name: errors errors_expense_attribute_id_23be4f13_fk_expense_attributes_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.errors + ADD CONSTRAINT errors_expense_attribute_id_23be4f13_fk_expense_attributes_id FOREIGN KEY (expense_attribute_id) REFERENCES public.expense_attributes(id) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: errors errors_expense_group_id_86fafc8b_fk_expense_groups_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.errors + ADD CONSTRAINT errors_expense_group_id_86fafc8b_fk_expense_groups_id FOREIGN KEY (expense_group_id) REFERENCES public.expense_groups(id) DEFERRABLE INITIALLY DEFERRED; + + +-- +-- Name: errors errors_workspace_id_a33dd61b_fk_workspaces_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.errors + ADD CONSTRAINT errors_workspace_id_a33dd61b_fk_workspaces_id FOREIGN KEY (workspace_id) REFERENCES public.workspaces(id) DEFERRABLE INITIALLY DEFERRED; + + -- -- Name: expense_fields expense_fields_workspace_id_b60af18c_fk_workspaces_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres -- @@ -13314,6 +13441,14 @@ ALTER TABLE ONLY public.vendor_payment_lineitems ADD CONSTRAINT vendor_payment_linei_vendor_payment_id_298cb06a_fk_vendor_pa FOREIGN KEY (vendor_payment_id) REFERENCES public.vendor_payments(id) DEFERRABLE INITIALLY DEFERRED; +-- +-- Name: workspace_schedules workspace_schedules_workspace_id_50ec990f_fk_workspaces_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres +-- + +ALTER TABLE ONLY public.workspace_schedules + ADD CONSTRAINT workspace_schedules_workspace_id_50ec990f_fk_workspaces_id FOREIGN KEY (workspace_id) REFERENCES public.workspaces(id) DEFERRABLE INITIALLY DEFERRED; + + -- -- Name: workspaces_user workspaces_user_user_id_4253baf7_fk_users_user_id; Type: FK CONSTRAINT; Schema: public; Owner: postgres -- @@ -13338,14 +13473,6 @@ ALTER TABLE ONLY public.workspace_schedules ADD CONSTRAINT workspaces_workspace_schedule_id_8274d659_fk_django_q_ FOREIGN KEY (schedule_id) REFERENCES public.django_q_schedule(id) DEFERRABLE INITIALLY DEFERRED; --- --- Name: workspace_schedules workspaces_workspace_workspace_id_3c3942bc_fk_workspace; Type: FK CONSTRAINT; Schema: public; Owner: postgres --- - -ALTER TABLE ONLY public.workspace_schedules - ADD CONSTRAINT workspaces_workspace_workspace_id_3c3942bc_fk_workspace FOREIGN KEY (workspace_id) REFERENCES public.workspaces(id) DEFERRABLE INITIALLY DEFERRED; - - -- -- PostgreSQL database dump complete -- diff --git a/tests/test_fyle/fixtures.py b/tests/test_fyle/fixtures.py index 24ba5d33..91dcf8b2 100644 --- a/tests/test_fyle/fixtures.py +++ b/tests/test_fyle/fixtures.py @@ -529,6 +529,7 @@ "expense_group_id": { "id": 1, "fund_source": "PERSONAL", + 'employee_name': 'Ashwin', "description": { "report_id": "rpuN3bgphxbK", "fund_source": "PERSONAL", From 28fc1e3d8b3f337b71f57e062fab1b978f831683 Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Wed, 22 Nov 2023 16:59:03 +0530 Subject: [PATCH 3/8] added field export_url in expense group and util to generate URL --- .../0028_expensegroup_export_url.py | 18 ++++++++++++++++++ apps/fyle/models.py | 1 + apps/netsuite/tasks.py | 15 +++++++++++++++ fyle_netsuite_api/utils.py | 19 +++++++++++++++++++ 4 files changed, 53 insertions(+) create mode 100644 apps/fyle/migrations/0028_expensegroup_export_url.py diff --git a/apps/fyle/migrations/0028_expensegroup_export_url.py b/apps/fyle/migrations/0028_expensegroup_export_url.py new file mode 100644 index 00000000..0bcdbbab --- /dev/null +++ b/apps/fyle/migrations/0028_expensegroup_export_url.py @@ -0,0 +1,18 @@ +# Generated by Django 3.1.14 on 2023-11-22 10:11 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('fyle', '0027_expensegroup_employee_name'), + ] + + operations = [ + migrations.AddField( + model_name='expensegroup', + name='export_url', + field=models.CharField(help_text='Netsuite URL for the exported expenses', max_length=255, null=True), + ), + ] diff --git a/apps/fyle/models.py b/apps/fyle/models.py index 13ae25b2..e167a4d9 100644 --- a/apps/fyle/models.py +++ b/apps/fyle/models.py @@ -328,6 +328,7 @@ class ExpenseGroup(models.Model): employee_name = models.CharField(max_length=100, help_text='Expense Group Employee Name', null=True) description = JSONField(max_length=255, help_text='Description', null=True) response_logs = JSONField(help_text='Reponse log of the export', null=True) + export_url = models.CharField(max_length=255, help_text='Netsuite URL for the exported expenses', null=True) created_at = models.DateTimeField(auto_now_add=True, help_text='Created at') exported_at = models.DateTimeField(help_text='Exported at', null=True) updated_at = models.DateTimeField(auto_now=True, help_text='Updated at') diff --git a/apps/netsuite/tasks.py b/apps/netsuite/tasks.py index 4398b6e8..6ba90a0a 100644 --- a/apps/netsuite/tasks.py +++ b/apps/netsuite/tasks.py @@ -11,6 +11,7 @@ from django.utils.module_loading import import_string from django_q.models import Schedule from django_q.tasks import Chain, async_task +from fyle_netsuite_api.utils import generate_netsuite_export_url from netsuitesdk.internal.exceptions import NetSuiteRequestError from netsuitesdk import NetSuiteRateLimitError, NetSuiteLoginError @@ -71,6 +72,13 @@ } +def add_export_url(response_logs, ns_account_id, expense_group): + try: + url = generate_netsuite_export_url(response_logs, ns_account_id) + expense_group.export_url = url + except Exception as exception: + logger.info({'error': exception}) + def load_attachments(netsuite_connection: NetSuiteConnector, expense: Expense, expense_group: ExpenseGroup): """ Get attachments from Fyle @@ -447,7 +455,11 @@ def create_bill(expense_group, task_log_id): expense_group.exported_at = datetime.now() expense_group.response_logs = created_bill + + add_export_url(response_logs=created_bill, ns_account_id=netsuite_credentials.ns_account_id, expense_group=expense_group) + expense_group.save() + async_task( 'apps.netsuite.tasks.upload_attachments_and_update_export', @@ -564,6 +576,7 @@ def create_credit_card_charge(expense_group, task_log_id): expense_group.exported_at = datetime.now() expense_group.response_logs = created_credit_card_charge + add_export_url(response_logs=created_credit_card_charge, ns_account_id=netsuite_credentials.ns_account_id, expense_group=expense_group) expense_group.save() except NetSuiteCredentials.DoesNotExist: @@ -654,6 +667,7 @@ def create_expense_report(expense_group, task_log_id): expense_group.exported_at = datetime.now() expense_group.response_logs = created_expense_report + add_export_url(response_logs=created_expense_report, ns_account_id=netsuite_credentials.ns_account_id, expense_group=expense_group) expense_group.save() async_task( @@ -749,6 +763,7 @@ def create_journal_entry(expense_group, task_log_id): expense_group.exported_at = datetime.now() expense_group.response_logs = created_journal_entry + add_export_url(response_logs=created_journal_entry, ns_account_id=netsuite_credentials.ns_account_id, expense_group=expense_group) expense_group.save() async_task( diff --git a/fyle_netsuite_api/utils.py b/fyle_netsuite_api/utils.py index e973f5ab..47a09110 100644 --- a/fyle_netsuite_api/utils.py +++ b/fyle_netsuite_api/utils.py @@ -23,3 +23,22 @@ def filter_queryset(self, queryset): filter_kwargs = {self.lookup_field: lookup_value} queryset = queryset.filter(**filter_kwargs) return super().filter_queryset(queryset) + + +export_type_redirection = { + 'vendorBill': 'vendbill', + 'expenseReport': 'exprept', + 'journalEntry': 'journal', + 'chargeCard': 'cardchrg', + 'chargeCardRefund': 'cardrfnd' + } + +def generate_netsuite_export_url(response_logs, ns_account_id): + + if response_logs: + export_type = response_logs['type'] if response_logs['type'] else 'chargeCard' + internal_id = response_logs['internalId'] + redirection = export_type_redirection[export_type] + url = f'https://{ns_account_id}.app.netsuite.com/app/accounting/transactions/${redirection}.nl?id={internal_id}' + return url + return None From 535c6196279195ade3fc13c13ca5b2571d27cafc Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Wed, 22 Nov 2023 21:35:51 +0530 Subject: [PATCH 4/8] updated test and fixtures --- scripts/python/update-export-url.py | 16 +++++++++++++++ .../reset_db_fixtures/reset_db.sql | 20 ++++++++++--------- tests/test_fyle/fixtures.py | 3 ++- 3 files changed, 29 insertions(+), 10 deletions(-) create mode 100644 scripts/python/update-export-url.py diff --git a/scripts/python/update-export-url.py b/scripts/python/update-export-url.py new file mode 100644 index 00000000..5cec6b3c --- /dev/null +++ b/scripts/python/update-export-url.py @@ -0,0 +1,16 @@ +from apps.fyle.models import ExpenseGroup +from apps.workspaces.models import NetSuiteCredentials +from fyle_netsuite_api.utils import generate_netsuite_export_url + + +expense_groups = ExpenseGroup.objects.all() + +for expense_group in expense_groups: + try: + netsuite_cred = NetSuiteCredentials.objects.get(workspace_id=expense_group.workspace_id) + url = generate_netsuite_export_url(response_logs=expense_group.response_logs, ns_account_id=netsuite_cred.ns_account_id) + expense_group.export_url = url + expense_group.save() + print('Export URl updated for expense group id {}'.format(expense_group.id)) + except Exception as exception: + print('Something went wrong during updating export_url for workspace_id {}'.format(expense_group.workspace_id)) diff --git a/tests/sql_fixtures/reset_db_fixtures/reset_db.sql b/tests/sql_fixtures/reset_db_fixtures/reset_db.sql index 84857da5..1488138b 100644 --- a/tests/sql_fixtures/reset_db_fixtures/reset_db.sql +++ b/tests/sql_fixtures/reset_db_fixtures/reset_db.sql @@ -927,7 +927,8 @@ CREATE TABLE public.expense_groups ( fund_source character varying(255) NOT NULL, exported_at timestamp with time zone, response_logs jsonb, - employee_name character varying(100) + employee_name character varying(100), + export_url character varying(255) ); @@ -7775,6 +7776,7 @@ COPY public.django_migrations (id, app, name, applied) FROM stdin; 172 fyle 0027_expensegroup_employee_name 2023-11-20 11:19:47.476133+00 173 workspaces 0036_auto_20231027_0709 2023-11-20 11:19:47.53547+00 174 tasks 0009_error 2023-11-20 11:19:47.609035+00 +175 fyle 0028_expensegroup_export_url 2023-11-22 11:49:48.090718+00 \. @@ -11364,13 +11366,13 @@ COPY public.expense_group_settings (id, reimbursable_expense_group_fields, corpo -- Data for Name: expense_groups; Type: TABLE DATA; Schema: public; Owner: postgres -- -COPY public.expense_groups (id, description, created_at, updated_at, workspace_id, fund_source, exported_at, response_logs, employee_name) FROM stdin; -1 {"report_id": "rpuN3bgphxbK", "fund_source": "PERSONAL", "claim_number": "C/2021/11/R/5", "employee_email": "ashwin.t@fyle.in"} 2021-11-15 10:29:07.618062+00 2021-11-15 11:02:55.125634+00 1 PERSONAL \N \N \N -2 {"report_id": "rpHLA9Dfp9hN", "fund_source": "CCC", "claim_number": "C/2021/11/R/6", "employee_email": "ashwin.t@fyle.in"} 2021-11-15 13:12:12.275539+00 2021-11-15 13:27:27.538211+00 1 CCC \N \N \N -3 {"report_id": "rpu5W0LYrk6e", "fund_source": "PERSONAL", "claim_number": "C/2021/11/R/2", "employee_email": "ashwin.t@fyle.in"} 2021-11-16 04:25:49.206777+00 2021-11-16 04:25:49.206809+00 2 PERSONAL \N \N \N -4 {"spent_at": "2021-11-16", "report_id": "rprqDvARHUnv", "expense_id": "txMLGb6Xy8m8", "fund_source": "CCC", "claim_number": "C/2021/11/R/1", "employee_email": "ashwin.t@fyle.in"} 2021-11-16 04:25:49.226855+00 2021-11-16 04:25:49.226855+00 2 CCC \N \N \N -47 {"report_id": "rpXqCutQj85N", "fund_source": "PERSONAL", "claim_number": "C/2021/12/R/1", "employee_email": "admin1@fyleforintacct.in"} 2021-12-03 11:26:58.731339+00 2021-12-03 11:26:58.731398+00 49 PERSONAL \N \N \N -48 {"report_id": "rpXqCutQj85N", "expense_id": "txcKVVELn1Vl", "fund_source": "CCC", "claim_number": "C/2021/12/R/1", "employee_email": "admin1@fyleforintacct.in"} 2021-12-03 11:26:58.746214+00 2021-12-03 11:26:58.746248+00 49 CCC \N \N \N +COPY public.expense_groups (id, description, created_at, updated_at, workspace_id, fund_source, exported_at, response_logs, employee_name, export_url) FROM stdin; +1 {"report_id": "rpuN3bgphxbK", "fund_source": "PERSONAL", "claim_number": "C/2021/11/R/5", "employee_email": "ashwin.t@fyle.in"} 2021-11-15 10:29:07.618062+00 2021-11-15 11:02:55.125634+00 1 PERSONAL \N \N \N \N +2 {"report_id": "rpHLA9Dfp9hN", "fund_source": "CCC", "claim_number": "C/2021/11/R/6", "employee_email": "ashwin.t@fyle.in"} 2021-11-15 13:12:12.275539+00 2021-11-15 13:27:27.538211+00 1 CCC \N \N \N \N +3 {"report_id": "rpu5W0LYrk6e", "fund_source": "PERSONAL", "claim_number": "C/2021/11/R/2", "employee_email": "ashwin.t@fyle.in"} 2021-11-16 04:25:49.206777+00 2021-11-16 04:25:49.206809+00 2 PERSONAL \N \N \N \N +4 {"spent_at": "2021-11-16", "report_id": "rprqDvARHUnv", "expense_id": "txMLGb6Xy8m8", "fund_source": "CCC", "claim_number": "C/2021/11/R/1", "employee_email": "ashwin.t@fyle.in"} 2021-11-16 04:25:49.226855+00 2021-11-16 04:25:49.226855+00 2 CCC \N \N \N \N +47 {"report_id": "rpXqCutQj85N", "fund_source": "PERSONAL", "claim_number": "C/2021/12/R/1", "employee_email": "admin1@fyleforintacct.in"} 2021-12-03 11:26:58.731339+00 2021-12-03 11:26:58.731398+00 49 PERSONAL \N \N \N \N +48 {"report_id": "rpXqCutQj85N", "expense_id": "txcKVVELn1Vl", "fund_source": "CCC", "claim_number": "C/2021/12/R/1", "employee_email": "admin1@fyleforintacct.in"} 2021-12-03 11:26:58.746214+00 2021-12-03 11:26:58.746248+00 49 CCC \N \N \N \N \. @@ -11662,7 +11664,7 @@ SELECT pg_catalog.setval('public.django_content_type_id_seq', 44, true); -- Name: django_migrations_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres -- -SELECT pg_catalog.setval('public.django_migrations_id_seq', 174, true); +SELECT pg_catalog.setval('public.django_migrations_id_seq', 175, true); -- diff --git a/tests/test_fyle/fixtures.py b/tests/test_fyle/fixtures.py index 91dcf8b2..15995fd7 100644 --- a/tests/test_fyle/fixtures.py +++ b/tests/test_fyle/fixtures.py @@ -542,6 +542,7 @@ "externalId": "03294720937402397402937", "internalId": "116142", }, + "export_url": "https://TSTDRV2089588.app.netsuite.com/app/accounting/transactions/$journal.nl?id=725456", "created_at": "2021-11-15T10:29:07.618062Z", "exported_at": "2021-11-15T11:02:55.125205Z", "updated_at": "2021-11-15T11:02:55.125634Z", @@ -54965,4 +54966,4 @@ ] } ], -} \ No newline at end of file +} From 0db7d9446c17ad75ab0271f6f09bbd147b238ab1 Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Mon, 27 Nov 2023 22:55:30 +0530 Subject: [PATCH 5/8] changed scripts to batch update export url --- apps/netsuite/tasks.py | 16 ++++------------ fyle_netsuite_api/utils.py | 19 +++++++++---------- scripts/python/update-export-url.py | 29 ++++++++++++++++++----------- 3 files changed, 31 insertions(+), 33 deletions(-) diff --git a/apps/netsuite/tasks.py b/apps/netsuite/tasks.py index 6ba90a0a..903503d2 100644 --- a/apps/netsuite/tasks.py +++ b/apps/netsuite/tasks.py @@ -72,13 +72,6 @@ } -def add_export_url(response_logs, ns_account_id, expense_group): - try: - url = generate_netsuite_export_url(response_logs, ns_account_id) - expense_group.export_url = url - except Exception as exception: - logger.info({'error': exception}) - def load_attachments(netsuite_connection: NetSuiteConnector, expense: Expense, expense_group: ExpenseGroup): """ Get attachments from Fyle @@ -455,8 +448,7 @@ def create_bill(expense_group, task_log_id): expense_group.exported_at = datetime.now() expense_group.response_logs = created_bill - - add_export_url(response_logs=created_bill, ns_account_id=netsuite_credentials.ns_account_id, expense_group=expense_group) + expense_group.url = generate_netsuite_export_url(response_logs=created_bill, ns_account_id=netsuite_credentials) expense_group.save() @@ -576,7 +568,7 @@ def create_credit_card_charge(expense_group, task_log_id): expense_group.exported_at = datetime.now() expense_group.response_logs = created_credit_card_charge - add_export_url(response_logs=created_credit_card_charge, ns_account_id=netsuite_credentials.ns_account_id, expense_group=expense_group) + expense_group.export_url = generate_netsuite_export_url(response_logs=created_credit_card_charge, ns_account_id=netsuite_credentials) expense_group.save() except NetSuiteCredentials.DoesNotExist: @@ -667,7 +659,7 @@ def create_expense_report(expense_group, task_log_id): expense_group.exported_at = datetime.now() expense_group.response_logs = created_expense_report - add_export_url(response_logs=created_expense_report, ns_account_id=netsuite_credentials.ns_account_id, expense_group=expense_group) + expense_group.export_url = generate_netsuite_export_url(response_logs=created_expense_report, ns_account_id=netsuite_credentials) expense_group.save() async_task( @@ -763,7 +755,7 @@ def create_journal_entry(expense_group, task_log_id): expense_group.exported_at = datetime.now() expense_group.response_logs = created_journal_entry - add_export_url(response_logs=created_journal_entry, ns_account_id=netsuite_credentials.ns_account_id, expense_group=expense_group) + expense_group.export_url = generate_netsuite_export_url(response_logs=created_journal_entry, ns_account_id=netsuite_credentials) expense_group.save() async_task( diff --git a/fyle_netsuite_api/utils.py b/fyle_netsuite_api/utils.py index 47a09110..e5f63da6 100644 --- a/fyle_netsuite_api/utils.py +++ b/fyle_netsuite_api/utils.py @@ -2,6 +2,14 @@ from rest_framework.serializers import ValidationError +EXPORT_TYPE_REDIRECTION = { + 'vendorBill': 'vendbill', + 'expenseReport': 'exprept', + 'journalEntry': 'journal', + 'chargeCard': 'cardchrg', + 'chargeCardRefund': 'cardrfnd' +} + def assert_valid(condition: bool, message: str) -> Response or None: """ Assert conditions @@ -24,21 +32,12 @@ def filter_queryset(self, queryset): queryset = queryset.filter(**filter_kwargs) return super().filter_queryset(queryset) - -export_type_redirection = { - 'vendorBill': 'vendbill', - 'expenseReport': 'exprept', - 'journalEntry': 'journal', - 'chargeCard': 'cardchrg', - 'chargeCardRefund': 'cardrfnd' - } def generate_netsuite_export_url(response_logs, ns_account_id): - if response_logs: export_type = response_logs['type'] if response_logs['type'] else 'chargeCard' internal_id = response_logs['internalId'] - redirection = export_type_redirection[export_type] + redirection = EXPORT_TYPE_REDIRECTION[export_type] url = f'https://{ns_account_id}.app.netsuite.com/app/accounting/transactions/${redirection}.nl?id={internal_id}' return url return None diff --git a/scripts/python/update-export-url.py b/scripts/python/update-export-url.py index 5cec6b3c..4a9ed357 100644 --- a/scripts/python/update-export-url.py +++ b/scripts/python/update-export-url.py @@ -1,16 +1,23 @@ from apps.fyle.models import ExpenseGroup -from apps.workspaces.models import NetSuiteCredentials +from apps.workspaces.models import NetSuiteCredentials, Workspace from fyle_netsuite_api.utils import generate_netsuite_export_url -expense_groups = ExpenseGroup.objects.all() +folder_created_workspace_ids = [] -for expense_group in expense_groups: - try: - netsuite_cred = NetSuiteCredentials.objects.get(workspace_id=expense_group.workspace_id) - url = generate_netsuite_export_url(response_logs=expense_group.response_logs, ns_account_id=netsuite_cred.ns_account_id) - expense_group.export_url = url - expense_group.save() - print('Export URl updated for expense group id {}'.format(expense_group.id)) - except Exception as exception: - print('Something went wrong during updating export_url for workspace_id {}'.format(expense_group.workspace_id)) +prod_workspaces = Workspace.objects.exclude( + name__iregex=r'(fyle|test)', + id__in=folder_created_workspace_ids +) + +for workspace in prod_workspaces: + page_size = 200 + expense_group_counts = ExpenseGroup.objects.filter(workspace_id=workspace.id, response_logs__isnull=False).count() + for offset in range(0, expense_group_counts, page_size): + expense_to_be_updated = [] + limit = offset + page_size + paginated_expense_groups = ExpenseGroup.objects.filter(workspace_id=workspace.id, response_logs__isnull=False)[offset:limit] + for expense_group in paginated_expense_groups: + netsuite_cred = NetSuiteCredentials.objects.get(workspace_id=workspace.id) + expense_group.export_url = generate_netsuite_export_url(response_logs=expense_group.response_logs, ns_account_id=netsuite_cred.ns_account_id) + expense_group.save() From 076f9d2e543538ce5b25c21a7ddce247fd1bdb2f Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Wed, 29 Nov 2023 02:15:05 +0530 Subject: [PATCH 6/8] bug fix --- fyle_netsuite_api/utils.py | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/fyle_netsuite_api/utils.py b/fyle_netsuite_api/utils.py index e5f63da6..21436106 100644 --- a/fyle_netsuite_api/utils.py +++ b/fyle_netsuite_api/utils.py @@ -1,6 +1,9 @@ from rest_framework.views import Response from rest_framework.serializers import ValidationError +import logging +logger = logging.getLogger(__name__) +logger.level = logging.INFO EXPORT_TYPE_REDIRECTION = { 'vendorBill': 'vendbill', @@ -35,9 +38,12 @@ def filter_queryset(self, queryset): def generate_netsuite_export_url(response_logs, ns_account_id): if response_logs: - export_type = response_logs['type'] if response_logs['type'] else 'chargeCard' - internal_id = response_logs['internalId'] - redirection = EXPORT_TYPE_REDIRECTION[export_type] - url = f'https://{ns_account_id}.app.netsuite.com/app/accounting/transactions/${redirection}.nl?id={internal_id}' - return url + try: + export_type = response_logs['type'] if response_logs['type'] else 'chargeCard' + internal_id = response_logs['internalId'] + redirection = EXPORT_TYPE_REDIRECTION[export_type] + url = f'https://{ns_account_id}.app.netsuite.com/app/accounting/transactions/${redirection}.nl?id={internal_id}' + return url + except Exception as exception: + logger.info({'error': exception}) return None From 9b0998e71b9542c9c90e4c17e0a2ce9df22c6c45 Mon Sep 17 00:00:00 2001 From: Ashutosh619-sudo Date: Wed, 29 Nov 2023 15:12:15 +0530 Subject: [PATCH 7/8] comment resolved --- fyle_netsuite_api/utils.py | 2 +- scripts/python/update-export-url.py | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/fyle_netsuite_api/utils.py b/fyle_netsuite_api/utils.py index 21436106..acf9cb77 100644 --- a/fyle_netsuite_api/utils.py +++ b/fyle_netsuite_api/utils.py @@ -45,5 +45,5 @@ def generate_netsuite_export_url(response_logs, ns_account_id): url = f'https://{ns_account_id}.app.netsuite.com/app/accounting/transactions/${redirection}.nl?id={internal_id}' return url except Exception as exception: - logger.info({'error': exception}) + logger.exception({'error': exception}) return None diff --git a/scripts/python/update-export-url.py b/scripts/python/update-export-url.py index 4a9ed357..53b85be1 100644 --- a/scripts/python/update-export-url.py +++ b/scripts/python/update-export-url.py @@ -3,11 +3,8 @@ from fyle_netsuite_api.utils import generate_netsuite_export_url -folder_created_workspace_ids = [] - prod_workspaces = Workspace.objects.exclude( name__iregex=r'(fyle|test)', - id__in=folder_created_workspace_ids ) for workspace in prod_workspaces: From cf736f5208dfda16601a852bf93a7bc901bf4fd0 Mon Sep 17 00:00:00 2001 From: Ashutosh singh <55102089+Ashutosh619-sudo@users.noreply.github.com> Date: Wed, 29 Nov 2023 03:52:14 -0800 Subject: [PATCH 8/8] added more fields in expense serializer for redirection (#458) * added more fields in expense serializer * Sync import API (#459) * added expense group sync API * minor changes * added url for expense group sync view --- apps/fyle/serializers.py | 20 +++++++++++--------- apps/fyle/tasks.py | 23 ++++++++++++++--------- apps/fyle/urls.py | 5 +++-- apps/fyle/views.py | 19 ++++++++++++++++++- tests/test_fyle/fixtures.py | 24 ++++++++++++++++++++++-- tests/test_fyle/test_views.py | 2 +- 6 files changed, 69 insertions(+), 24 deletions(-) diff --git a/apps/fyle/serializers.py b/apps/fyle/serializers.py index 0cc5d045..71d608e1 100644 --- a/apps/fyle/serializers.py +++ b/apps/fyle/serializers.py @@ -5,13 +5,24 @@ from .models import Expense, ExpenseFilter, ExpenseGroup, ExpenseGroupSettings +class ExpenseSerializer(serializers.ModelSerializer): + """ + Expense serializer + """ + class Meta: + model = Expense + fields = ['updated_at', 'claim_number', 'employee_email', 'employee_name', 'fund_source', 'expense_number', 'vendor', 'category', 'amount', + 'report_id', 'settlement_id', 'expense_id'] + class ExpenseGroupSerializer(serializers.ModelSerializer): """ Expense group serializer """ + expenses = ExpenseSerializer(many=True) class Meta: model = ExpenseGroup fields = '__all__' + extra_fields = ['expenses'] class ExpenseGroupExpenseSerializer(serializers.ModelSerializer): @@ -60,12 +71,3 @@ def create(self, validated_data): ) return expense_filter - - -class ExpenseSerializer(serializers.ModelSerializer): - """ - Expense serializer - """ - class Meta: - model = Expense - fields = ['updated_at', 'claim_number', 'employee_email', 'employee_name', 'fund_source'] diff --git a/apps/fyle/tasks.py b/apps/fyle/tasks.py index f3ed39f8..e3b9ab40 100644 --- a/apps/fyle/tasks.py +++ b/apps/fyle/tasks.py @@ -24,27 +24,32 @@ 'CCC': 'PERSONAL_CORPORATE_CREDIT_CARD_ACCOUNT' } -def schedule_expense_group_creation(workspace_id: int): - """ - Schedule Expense group creation - :param workspace_id: Workspace id - :param user: User email - :return: None - """ +def get_task_log_and_fund_source(workspace_id: int): task_log, _ = TaskLog.objects.update_or_create( workspace_id=workspace_id, type='FETCHING_EXPENSES', defaults={ - 'status': 'IN_PROGRESS' + 'status': 'IN_PROGRESS' } ) configuration = Configuration.objects.get(workspace_id=workspace_id) - fund_source = ['PERSONAL'] if configuration.corporate_credit_card_expenses_object is not None: fund_source.append('CCC') + return task_log, fund_source, configuration + +def schedule_expense_group_creation(workspace_id: int): + """ + Schedule Expense group creation + :param workspace_id: Workspace id + :param user: User email + :return: None + """ + + task_log, fund_source, configuration = get_task_log_and_fund_source(workspace_id) + async_task('apps.fyle.tasks.create_expense_groups', workspace_id, configuration, fund_source, task_log) diff --git a/apps/fyle/urls.py b/apps/fyle/urls.py index ceee784b..2333ba8c 100644 --- a/apps/fyle/urls.py +++ b/apps/fyle/urls.py @@ -2,7 +2,7 @@ from django.urls import path -from .views import ExpenseGroupView, ExpenseGroupByIdView, ExpenseGroupScheduleView, ExportableExpenseGroupsView, FyleFieldsView, ExpenseView,\ +from .views import ExpenseGroupSyncView, ExpenseGroupView, ExpenseGroupByIdView, ExpenseGroupScheduleView, ExportableExpenseGroupsView, FyleFieldsView, ExpenseView,\ ExpenseAttributesView, ExpenseGroupSettingsView, SyncFyleDimensionView, RefreshFyleDimensionView,\ ExpenseGroupCountView, ExpenseFilterView, ExpenseGroupExpenseView, CustomFieldView @@ -13,7 +13,8 @@ path('expense_groups//', ExpenseGroupByIdView.as_view(), name='expense-group-by-id'), path('expense_groups//expenses/', ExpenseGroupExpenseView.as_view(), name='expense-group-expenses'), path('expense_group_settings/', ExpenseGroupSettingsView.as_view(), name='expense-group-settings'), - path('exportable_expense_groups/', ExportableExpenseGroupsView.as_view(), name='expense-expense-groups') + path('exportable_expense_groups/', ExportableExpenseGroupsView.as_view(), name='expense-expense-groups'), + path('expense_groups/sync/', ExpenseGroupSyncView.as_view(), name='sync-expense-groups'), ] fyle_dimension_paths = [ diff --git a/apps/fyle/views.py b/apps/fyle/views.py index 561d0670..75ad45fc 100644 --- a/apps/fyle/views.py +++ b/apps/fyle/views.py @@ -14,7 +14,7 @@ from apps.workspaces.models import Configuration, FyleCredential, Workspace -from .tasks import schedule_expense_group_creation +from .tasks import schedule_expense_group_creation, get_task_log_and_fund_source, create_expense_groups from .helpers import check_interval_and_sync_dimension, sync_dimensions from .models import Expense, ExpenseGroup, ExpenseGroupSettings, ExpenseFilter from .serializers import ExpenseGroupSerializer, ExpenseSerializer, ExpenseFieldSerializer, \ @@ -419,3 +419,20 @@ def get(self, request, *args, **kwargs): }, status=status.HTTP_400_BAD_REQUEST ) + + +class ExpenseGroupSyncView(generics.CreateAPIView): + """ + Create expense groups + """ + def post(self, request, *args, **kwargs): + """ + Post expense groups creation + """ + task_log, fund_source, configuration = get_task_log_and_fund_source(kwargs['workspace_id']) + + create_expense_groups(kwargs['workspace_id'], configuration ,fund_source, task_log) + + return Response( + status=status.HTTP_200_OK + ) diff --git a/tests/test_fyle/fixtures.py b/tests/test_fyle/fixtures.py index 15995fd7..81690a29 100644 --- a/tests/test_fyle/fixtures.py +++ b/tests/test_fyle/fixtures.py @@ -131,7 +131,14 @@ 'claim_number': ' C/2021/12/R/198', 'employee_email': 'jhonsnow@fyle.in', 'employee_name': None, - 'fund_source': 'CCC' + 'fund_source': 'CCC', + 'expense_number': 'E/2023/09/T/7', + 'vendor': None, + 'category': 'Train', + 'amount': 101.0, + 'report_id': 'dummy_report_id', + 'settlement_id': 'dummy_settlement_id', + 'expense_id': 'dummy_expense_id' }, { 'updated_at': '2021-12-03T11:26:58.702209Z', @@ -547,7 +554,20 @@ "exported_at": "2021-11-15T11:02:55.125205Z", "updated_at": "2021-11-15T11:02:55.125634Z", "workspace": 1, - "expenses": [1], + "expenses": [ { + "updated_at": "2023-11-21T10:41:09.919000Z", + "claim_number": "C/2023/06/R/4", + "employee_email": "admin1@fyleforbadassashu.in", + "employee_name": "Theresa Brown", + "fund_source": "PERSONAL", + "expense_number": "E/2023/06/T/21", + "vendor": "95110", + "category": "Airlines", + "amount": 6377.0, + "report_id": "rp0kaXoqkJle", + "settlement_id": "setPzkM7eyQFd", + "expense_id": "txyZ1zJDQfiK" + }], }, "expense_group_setting_response": { "id": 1, diff --git a/tests/test_fyle/test_views.py b/tests/test_fyle/test_views.py index bcc8add0..81889754 100644 --- a/tests/test_fyle/test_views.py +++ b/tests/test_fyle/test_views.py @@ -401,4 +401,4 @@ def test_exportable_expense_group_view(api_client, access_token): assert response.status_code==200 response = json.loads(response.content) - assert response['exportable_expense_group_ids'] == [1, 2] \ No newline at end of file + assert response['exportable_expense_group_ids'] == [1, 2]