Skip to content

Commit e903127

Browse files
Ashutosh619-sudoAshutosh619-sudo
andauthored
Feat: Add and update regional date setting on Org settings update (#891)
* Feat: Add and update regional date setting on Org settings update * comment resolved * covered all lines * comment resolved --------- Co-authored-by: Ashutosh619-sudo <ashutosh.s@fyle.com>
1 parent eb01109 commit e903127

File tree

10 files changed

+192
-5
lines changed

10 files changed

+192
-5
lines changed

apps/fyle/queue.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,20 @@ def handle_webhook_callback(body: dict, workspace_id: int) -> None:
8686
}
8787
publish_to_rabbitmq(payload=payload, routing_key=RoutingKeyEnum.UTILITY.value)
8888

89+
elif (
90+
action == WebhookCallbackActionEnum.UPDATED.value
91+
and resource == 'ORG_SETTING'
92+
):
93+
payload = {
94+
'workspace_id': workspace_id,
95+
'action': WorkerActionEnum.ORG_SETTING_UPDATED.value,
96+
'data': {
97+
'workspace_id': workspace_id,
98+
'org_settings': data
99+
}
100+
}
101+
publish_to_rabbitmq(payload=payload, routing_key=RoutingKeyEnum.UTILITY.value)
102+
89103
elif action in (WebhookCallbackActionEnum.CREATED, WebhookCallbackActionEnum.UPDATED, WebhookCallbackActionEnum.DELETED):
90104
try:
91105
fyle_webhook_sync_enabled = FeatureConfig.get_feature_config(workspace_id=workspace_id, key='fyle_webhook_sync_enabled')

apps/fyle/tasks.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1015,3 +1015,21 @@ def _handle_expense_ejected_from_report(expense: Expense, expense_data: dict, wo
10151015
delete_expense_group_and_related_data(expense_group, workspace.id)
10161016
else:
10171017
worker_logger.info("Expense group %s still has expenses after removing %s", expense_group.id, expense.expense_id)
1018+
1019+
1020+
def handle_org_setting_updated(workspace_id: int, org_settings: dict) -> None:
1021+
"""
1022+
Update regional date setting on org setting updated
1023+
:param workspace_id: Workspace id
1024+
:param org_settings: Org settings
1025+
:return: None
1026+
"""
1027+
worker_logger = get_logger()
1028+
worker_logger.info("Handling org settings update for workspace %s", workspace_id)
1029+
1030+
workspace = Workspace.objects.get(id=workspace_id)
1031+
workspace.org_settings = {
1032+
'regional_settings': org_settings.get('regional_settings', {})
1033+
}
1034+
workspace.save(update_fields=['org_settings', 'updated_at'])
1035+
worker_logger.info("Updated org settings for workspace %s", workspace.id)
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated by Django 4.2.27 on 2026-01-12 11:50
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('workspaces', '0059_featureconfig_import_billable_field_for_projects'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='workspace',
15+
name='org_settings',
16+
field=models.JSONField(default=dict, help_text='Org Settings'),
17+
),
18+
]

apps/workspaces/models.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ class Workspace(models.Model):
9898
max_length=50, choices=ONBOARDING_STATE_CHOICES, default=get_default_onboarding_state,
9999
help_text='Onboarding status of the workspace', null=True
100100
)
101+
org_settings = JSONField(help_text='Org Settings', default=dict)
101102
created_at = models.DateTimeField(auto_now_add=True, help_text='Created at datetime')
102103
updated_at = models.DateTimeField(auto_now=True, help_text='Updated at datetime')
103104

tests/sql_fixtures/reset_db_fixtures/reset_db.sql

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55

66
-- Dumped from database version 15.15 (Debian 15.15-1.pgdg13+1)
7-
-- Dumped by pg_dump version 17.6 (Debian 17.6-0+deb13u1)
7+
-- Dumped by pg_dump version 17.7 (Debian 17.7-0+deb13u1)
88

99
SET statement_timeout = 0;
1010
SET lock_timeout = 0;
@@ -3069,7 +3069,8 @@ CREATE TABLE public.workspaces (
30693069
cluster_domain character varying(255),
30703070
ccc_last_synced_at timestamp with time zone,
30713071
onboarding_state character varying(50),
3072-
app_version character varying(2) NOT NULL
3072+
app_version character varying(2) NOT NULL,
3073+
org_settings jsonb NOT NULL
30733074
);
30743075

30753076

@@ -6437,6 +6438,7 @@ COPY public.django_migrations (id, app, name, applied) FROM stdin;
64376438
277 workspaces 0058_remove_sageintacctcredential_refresh_token_and_more 2025-12-16 11:22:38.025898+00
64386439
278 internal 0028_auto_generated_sql 2026-01-08 06:56:29.613764+00
64396440
279 workspaces 0059_featureconfig_import_billable_field_for_projects 2026-01-08 06:56:29.634426+00
6441+
280 workspaces 0060_workspace_org_settings 2026-01-12 12:21:09.648554+00
64406442
\.
64416443

64426444

@@ -10410,8 +10412,8 @@ COPY public.workspace_schedules (id, enabled, start_datetime, interval_hours, sc
1041010412
-- Data for Name: workspaces; Type: TABLE DATA; Schema: public; Owner: postgres
1041110413
--
1041210414

10413-
COPY public.workspaces (id, name, fyle_org_id, last_synced_at, created_at, updated_at, destination_synced_at, source_synced_at, cluster_domain, ccc_last_synced_at, onboarding_state, app_version) FROM stdin;
10414-
1 Fyle For Arkham Asylum or79Cob97KSh 2022-09-20 08:56:50.098426+00 2022-09-20 08:38:03.352044+00 2022-09-20 08:56:50.098865+00 2022-09-28 11:56:39.11276+00 2022-09-28 11:55:42.90121+00 https://staging.fyle.tech \N IMPORT_SETTINGS v1
10415+
COPY public.workspaces (id, name, fyle_org_id, last_synced_at, created_at, updated_at, destination_synced_at, source_synced_at, cluster_domain, ccc_last_synced_at, onboarding_state, app_version, org_settings) FROM stdin;
10416+
1 Fyle For Arkham Asylum or79Cob97KSh 2022-09-20 08:56:50.098426+00 2022-09-20 08:38:03.352044+00 2022-09-20 08:56:50.098865+00 2022-09-28 11:56:39.11276+00 2022-09-28 11:55:42.90121+00 https://staging.fyle.tech \N IMPORT_SETTINGS v1 {}
1041510417
\.
1041610418

1041710419

@@ -10512,7 +10514,7 @@ SELECT pg_catalog.setval('public.django_content_type_id_seq', 57, true);
1051210514
-- Name: django_migrations_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
1051310515
--
1051410516

10515-
SELECT pg_catalog.setval('public.django_migrations_id_seq', 279, true);
10517+
SELECT pg_catalog.setval('public.django_migrations_id_seq', 280, true);
1051610518

1051710519

1051810520
--

tests/test_fyle/fixtures.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7497,5 +7497,46 @@
74977497
'sub_category': '',
74987498
'is_enabled': True
74997499
}
7500+
},
7501+
'org_settings': {
7502+
'org_settings_payload': {
7503+
'regional_settings': {
7504+
'locale': {
7505+
'date_format': 'DD/MM/YYYY',
7506+
'timezone': 'Asia/Kolkata'
7507+
}
7508+
},
7509+
'other_setting': 'should_be_ignored'
7510+
},
7511+
'org_settings_payload_without_regional': {
7512+
'some_other_setting': 'value'
7513+
},
7514+
'org_settings_payload_updated': {
7515+
'regional_settings': {
7516+
'locale': {
7517+
'date_format': 'YYYY-MM-DD',
7518+
'timezone': 'Europe/London'
7519+
}
7520+
}
7521+
},
7522+
'expected_org_settings': {
7523+
'regional_settings': {
7524+
'locale': {
7525+
'date_format': 'DD/MM/YYYY',
7526+
'timezone': 'Asia/Kolkata'
7527+
}
7528+
}
7529+
},
7530+
'expected_org_settings_empty': {
7531+
'regional_settings': {}
7532+
},
7533+
'expected_org_settings_updated': {
7534+
'regional_settings': {
7535+
'locale': {
7536+
'date_format': 'YYYY-MM-DD',
7537+
'timezone': 'Europe/London'
7538+
}
7539+
}
7540+
}
75007541
}
75017542
}

tests/test_fyle/test_queue.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,3 +200,36 @@ def test_handle_webhook_callback_attribute_exception(db, add_webhook_attribute_d
200200
handle_webhook_callback(webhook_body, workspace.id)
201201
mock_processor.assert_called_once()
202202
mock_logger.error.assert_called_once_with(f'Error processing attribute webhook for workspace {workspace.id}: Test exception')
203+
204+
205+
def test_handle_webhook_callback_org_setting_updated(db, mocker):
206+
"""
207+
Test handle_webhook_callback for ORG_SETTING UPDATED action
208+
"""
209+
workspace = Workspace.objects.get(id=1)
210+
211+
mock_publish = mocker.patch('apps.fyle.queue.publish_to_rabbitmq')
212+
213+
webhook_body = {
214+
'action': 'UPDATED',
215+
'resource': 'ORG_SETTING',
216+
'data': {
217+
'regional_settings': {
218+
'locale': {
219+
'date_format': 'DD/MM/YYYY',
220+
'timezone': 'Asia/Kolkata'
221+
}
222+
}
223+
}
224+
}
225+
226+
handle_webhook_callback(webhook_body, workspace.id)
227+
228+
mock_publish.assert_called_once()
229+
call_args = mock_publish.call_args
230+
payload = call_args[1]['payload']
231+
232+
assert payload['workspace_id'] == workspace.id
233+
assert payload['action'] == 'UTILITY.ORG_SETTING_UPDATED'
234+
assert payload['data']['workspace_id'] == workspace.id
235+
assert payload['data']['org_settings'] == webhook_body['data']

tests/test_fyle/test_task.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
handle_expense_fund_source_change,
2525
handle_expense_report_change,
2626
handle_fund_source_changes_for_expense_ids,
27+
handle_org_setting_updated,
2728
import_and_export_expenses,
2829
process_expense_group_for_fund_source_update,
2930
recreate_expense_groups,
@@ -1728,3 +1729,59 @@ def test_update_non_exported_expenses_category_change(mocker, db):
17281729
assert mock_handle_category_changes.call_count == 3
17291730
_, kwargs = mock_handle_category_changes.call_args
17301731
assert kwargs['new_category'] == 'New Cat'
1732+
1733+
1734+
def test_handle_org_setting_updated(db):
1735+
"""
1736+
Test handle_org_setting_updated stores regional_settings in org_settings field
1737+
"""
1738+
workspace_id = 1
1739+
workspace = Workspace.objects.get(id=workspace_id)
1740+
1741+
workspace.org_settings = {}
1742+
workspace.save()
1743+
1744+
handle_org_setting_updated(
1745+
workspace_id=workspace_id,
1746+
org_settings=data['org_settings']['org_settings_payload']
1747+
)
1748+
1749+
workspace.refresh_from_db()
1750+
1751+
assert workspace.org_settings == data['org_settings']['expected_org_settings']
1752+
assert 'other_setting' not in workspace.org_settings
1753+
1754+
1755+
def test_handle_org_setting_updated_empty_regional_settings(db):
1756+
"""
1757+
Test handle_org_setting_updated when regional_settings is empty or missing
1758+
"""
1759+
workspace_id = 1
1760+
workspace = Workspace.objects.get(id=workspace_id)
1761+
1762+
handle_org_setting_updated(
1763+
workspace_id=workspace_id,
1764+
org_settings=data['org_settings']['org_settings_payload_without_regional']
1765+
)
1766+
1767+
workspace.refresh_from_db()
1768+
assert workspace.org_settings == data['org_settings']['expected_org_settings_empty']
1769+
1770+
1771+
def test_handle_org_setting_updated_overwrites_existing(db):
1772+
"""
1773+
Test handle_org_setting_updated overwrites existing org_settings
1774+
"""
1775+
workspace_id = 1
1776+
workspace = Workspace.objects.get(id=workspace_id)
1777+
1778+
workspace.org_settings = data['org_settings']['expected_org_settings']
1779+
workspace.save()
1780+
1781+
handle_org_setting_updated(
1782+
workspace_id=workspace_id,
1783+
org_settings=data['org_settings']['org_settings_payload_updated']
1784+
)
1785+
1786+
workspace.refresh_from_db()
1787+
assert workspace.org_settings == data['org_settings']['expected_org_settings_updated']

tests/test_workspaces/fixtures.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@
5151
"user": [1],
5252
"onboarding_state": "COMPLETE",
5353
"app_version": "v1",
54+
"org_settings": {},
5455
},
5556
"expenses": [
5657
{

workers/helpers.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ class WorkerActionEnum(str, Enum):
4242
CHECK_INTERVAL_AND_SYNC_SAGE_INTACCT_DIMENSION = 'IMPORT.CHECK_INTERVAL_AND_SYNC_SAGE_INTACCT_DIMENSION'
4343
CHECK_SAGE_INTACCT_OBJECT_STATUS_AND_PROCESS_FYLE_REIMBURSEMENTS = 'EXPORT.P1.CHECK_SAGE_INTACCT_OBJECT_STATUS_AND_PROCESS_FYLE_REIMBURSEMENTS'
4444
EXPENSE_ADDED_EJECTED_FROM_REPORT = 'UTILITY.EXPENSE_ADDED_EJECTED_FROM_REPORT'
45+
ORG_SETTING_UPDATED = 'UTILITY.ORG_SETTING_UPDATED'
4546

4647

4748
QUEUE_BINDKEY_MAP = {
@@ -76,6 +77,7 @@ class WorkerActionEnum(str, Enum):
7677
WorkerActionEnum.CHECK_INTERVAL_AND_SYNC_SAGE_INTACCT_DIMENSION: 'apps.sage_intacct.helpers.check_interval_and_sync_dimension',
7778
WorkerActionEnum.CHECK_SAGE_INTACCT_OBJECT_STATUS_AND_PROCESS_FYLE_REIMBURSEMENTS: 'apps.sage_intacct.tasks.check_sage_intacct_object_status_and_process_fyle_reimbursements',
7879
WorkerActionEnum.EXPENSE_ADDED_EJECTED_FROM_REPORT: 'apps.fyle.tasks.handle_expense_report_change',
80+
WorkerActionEnum.ORG_SETTING_UPDATED: 'apps.fyle.tasks.handle_org_setting_updated',
7981
}
8082

8183

0 commit comments

Comments
 (0)