Skip to content

Commit 0273461

Browse files
authored
feat: add feature flag for import billable field for project (#889)
1 parent c50af4a commit 0273461

File tree

5 files changed

+94
-7
lines changed

5 files changed

+94
-7
lines changed

apps/workspaces/enums.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,4 @@ class CacheKeyEnum(str, Enum):
88
FYLE_SYNC_DIMENSIONS = "sync_dimensions_{workspace_id}"
99
SAGE_INTACCT_SYNC_DIMENSIONS = "sync_sage_intacct_dimensions_{workspace_id}"
1010
FEATURE_CONFIG_MIGRATED_TO_REST_API = "migrated_to_rest_api_{workspace_id}"
11+
FEATURE_CONFIG_IMPORT_BILLABLE_FIELD_FOR_PROJECTS = "import_billable_field_for_projects_{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-08 06:53
2+
3+
from django.db import migrations, models
4+
5+
6+
class Migration(migrations.Migration):
7+
8+
dependencies = [
9+
('workspaces', '0058_remove_sageintacctcredential_refresh_token_and_more'),
10+
]
11+
12+
operations = [
13+
migrations.AddField(
14+
model_name='featureconfig',
15+
name='import_billable_field_for_projects',
16+
field=models.BooleanField(default=False, help_text='Import billable field for projects'),
17+
),
18+
]

apps/workspaces/models.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ class FeatureConfig(models.Model):
266266
import_via_rabbitmq = models.BooleanField(default=True, help_text='Enable import via rabbitmq')
267267
fyle_webhook_sync_enabled = models.BooleanField(default=True, help_text='Enable fyle attribute webhook sync')
268268
migrated_to_rest_api = models.BooleanField(default=False, help_text='Migrated to using rest api')
269+
import_billable_field_for_projects = models.BooleanField(default=False, help_text='Import billable field for projects')
269270
created_at = models.DateTimeField(auto_now_add=True, help_text='Created at datetime')
270271
updated_at = models.DateTimeField(auto_now=True, help_text='Updated at datetime')
271272

@@ -281,7 +282,8 @@ def get_feature_config(cls, workspace_id: int, key: str) -> bool:
281282
cache_key_map = {
282283
'export_via_rabbitmq': CacheKeyEnum.FEATURE_CONFIG_EXPORT_VIA_RABBITMQ,
283284
'fyle_webhook_sync_enabled': CacheKeyEnum.FEATURE_CONFIG_FYLE_WEBHOOK_SYNC_ENABLED,
284-
'migrated_to_rest_api': WorkspaceCacheKeyEnum.FEATURE_CONFIG_MIGRATED_TO_REST_API
285+
'migrated_to_rest_api': WorkspaceCacheKeyEnum.FEATURE_CONFIG_MIGRATED_TO_REST_API,
286+
'import_billable_field_for_projects': WorkspaceCacheKeyEnum.FEATURE_CONFIG_IMPORT_BILLABLE_FIELD_FOR_PROJECTS
285287
}
286288

287289
cache_key_enum = cache_key_map.get(key)

apps/workspaces/views.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,11 @@ def post(self, request: Request) -> Response:
143143
ExpenseGroupSettings.objects.create(workspace_id=workspace.id)
144144

145145
LastExportDetail.objects.create(workspace_id=workspace.id)
146-
FeatureConfig.objects.create(workspace_id=workspace.id, migrated_to_rest_api=settings.BRAND_ID == 'fyle')
146+
FeatureConfig.objects.create(
147+
workspace_id=workspace.id,
148+
migrated_to_rest_api=settings.BRAND_ID == 'fyle',
149+
import_billable_field_for_projects=settings.BRAND_ID == 'fyle'
150+
)
147151
FyleSyncTimestamp.objects.create(workspace_id=workspace.id)
148152
IntacctSyncedTimestamp.objects.create(workspace_id=workspace.id)
149153
SageIntacctAttributesCount.objects.create(workspace_id=workspace.id)

tests/sql_fixtures/reset_db_fixtures/reset_db.sql

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

55

6-
-- Dumped from database version 15.14 (Debian 15.14-1.pgdg13+1)
6+
-- Dumped from database version 15.15 (Debian 15.15-1.pgdg13+1)
77
-- Dumped by pg_dump version 17.6 (Debian 17.6-0+deb13u1)
88

99
SET statement_timeout = 0;
@@ -17,6 +17,65 @@ SET xmloption = content;
1717
SET client_min_messages = warning;
1818
SET row_security = off;
1919

20+
--
21+
-- Name: add_tables_to_publication(); Type: FUNCTION; Schema: public; Owner: postgres
22+
--
23+
24+
CREATE FUNCTION public.add_tables_to_publication() RETURNS event_trigger
25+
LANGUAGE plpgsql
26+
AS $$
27+
DECLARE
28+
obj record;
29+
schema_name text;
30+
table_name text;
31+
BEGIN
32+
FOR obj IN
33+
SELECT * FROM pg_event_trigger_ddl_commands()
34+
WHERE command_tag = 'CREATE TABLE'
35+
LOOP
36+
RAISE NOTICE 'Processing new table: %', obj.object_identity;
37+
--- The format of the object_identity is schema.table
38+
schema_name := split_part(obj.object_identity, '.', 1);
39+
table_name := split_part(obj.object_identity, '.', 2);
40+
41+
-- Skip if not in public schema
42+
IF schema_name <> 'public' THEN
43+
CONTINUE;
44+
END IF;
45+
46+
-- Skip excluded system tables
47+
IF table_name IN (
48+
'django_admin_log',
49+
'django_content_type',
50+
'django_migrations',
51+
'django_q_ormq',
52+
'django_q_schedule',
53+
'django_q_task',
54+
'django_session',
55+
'expense_attributes_deletion_cache'
56+
) THEN
57+
RAISE NOTICE 'Skipping excluded table: %.%', schema_name, table_name;
58+
CONTINUE;
59+
END IF;
60+
61+
RAISE NOTICE 'Processing new table: %.%', schema_name, table_name;
62+
63+
-- Set REPLICA IDENTITY FULL
64+
EXECUTE format('ALTER TABLE %I.%I REPLICA IDENTITY FULL', schema_name, table_name);
65+
66+
-- Add to publication (ignore duplicates)
67+
BEGIN
68+
EXECUTE format('ALTER PUBLICATION events ADD TABLE %I.%I', schema_name, table_name);
69+
EXCEPTION WHEN duplicate_object THEN
70+
RAISE NOTICE 'Table %.% already in publication.', schema_name, table_name;
71+
END;
72+
END LOOP;
73+
END;
74+
$$;
75+
76+
77+
ALTER FUNCTION public.add_tables_to_publication() OWNER TO postgres;
78+
2079
--
2180
-- Name: delete_failed_expenses(integer, boolean, integer[]); Type: FUNCTION; Schema: public; Owner: postgres
2281
--
@@ -3082,7 +3141,8 @@ CREATE TABLE public.feature_configs (
30823141
workspace_id integer NOT NULL,
30833142
import_via_rabbitmq boolean NOT NULL,
30843143
fyle_webhook_sync_enabled boolean NOT NULL,
3085-
migrated_to_rest_api boolean NOT NULL
3144+
migrated_to_rest_api boolean NOT NULL,
3145+
import_billable_field_for_projects boolean NOT NULL
30863146
);
30873147

30883148

@@ -6375,6 +6435,8 @@ COPY public.django_migrations (id, app, name, applied) FROM stdin;
63756435
275 internal 0027_auto_generated_sql 2025-12-16 11:22:37.989849+00
63766436
276 sage_intacct 0034_chargecardtransactionlineitem_employee_id_and_more 2025-12-16 11:22:38.004807+00
63776437
277 workspaces 0058_remove_sageintacctcredential_refresh_token_and_more 2025-12-16 11:22:38.025898+00
6438+
278 internal 0028_auto_generated_sql 2026-01-08 06:56:29.613764+00
6439+
279 workspaces 0059_featureconfig_import_billable_field_for_projects 2026-01-08 06:56:29.634426+00
63786440
\.
63796441

63806442

@@ -9832,8 +9894,8 @@ COPY public.failed_events (id, routing_key, payload, created_at, updated_at, err
98329894
-- Data for Name: feature_configs; Type: TABLE DATA; Schema: public; Owner: postgres
98339895
--
98349896

9835-
COPY public.feature_configs (id, export_via_rabbitmq, created_at, updated_at, workspace_id, import_via_rabbitmq, fyle_webhook_sync_enabled, migrated_to_rest_api) FROM stdin;
9836-
1 f 2025-10-10 09:38:10.289737+00 2025-10-10 09:38:10.289737+00 1 f t f
9897+
COPY public.feature_configs (id, export_via_rabbitmq, created_at, updated_at, workspace_id, import_via_rabbitmq, fyle_webhook_sync_enabled, migrated_to_rest_api, import_billable_field_for_projects) FROM stdin;
9898+
1 f 2025-10-10 09:38:10.289737+00 2025-10-10 09:38:10.289737+00 1 f t f f
98379899
\.
98389900

98399901

@@ -10450,7 +10512,7 @@ SELECT pg_catalog.setval('public.django_content_type_id_seq', 57, true);
1045010512
-- Name: django_migrations_id_seq; Type: SEQUENCE SET; Schema: public; Owner: postgres
1045110513
--
1045210514

10453-
SELECT pg_catalog.setval('public.django_migrations_id_seq', 277, true);
10515+
SELECT pg_catalog.setval('public.django_migrations_id_seq', 279, true);
1045410516

1045510517

1045610518
--

0 commit comments

Comments
 (0)