From 1a02af213d4693ad0f3e3f99f5ca2808a7a92c6d Mon Sep 17 00:00:00 2001 From: A R R R Associates Date: Sat, 8 Aug 2026 15:02:30 +0530 Subject: [PATCH] Add System and Firm Admin task controls --- .../templates/services/catalogue_detail.html | 105 +++++++++++++++++- .../services/task_template_detail.html | 16 ++- app/modules/services/ui.py | 54 +++++++++ 3 files changed, 171 insertions(+), 4 deletions(-) diff --git a/app/modules/services/templates/services/catalogue_detail.html b/app/modules/services/templates/services/catalogue_detail.html index bacfaee..0beaf93 100644 --- a/app/modules/services/templates/services/catalogue_detail.html +++ b/app/modules/services/templates/services/catalogue_detail.html @@ -145,12 +145,111 @@
-

System Default Tasks

{% if can_edit %}Manage{% endif %}
+
+
+

System Default Tasks

+

System Admin controls the standard task template used as the base for firms.

+
+ {% if is_system_admin and can_edit %} + Manage Defaults + {% endif %} +
+
{% for task in default_templates %} -
{{ task.sequence_no }}. {{ task.task_name }}
Role: {{ task.default_role_name or '-' }} · Mandatory: {{ 'Yes' if task.is_mandatory else 'No' }} · Review: {{ 'Yes' if task.requires_review else 'No' }}
{% if task.description %}

{{ task.description }}

{% endif %}
- {% else %}
No system default tasks configured yet.
{% endfor %} +
+
+
+
{{ task.sequence_no }}. {{ task.task_name }}
+
+ Role: {{ task.default_role_name or '-' }} · + Mandatory: {{ 'Yes' if task.is_mandatory else 'No' }} · + Review: {{ 'Yes' if task.requires_review else 'No' }} · + {{ 'Active' if task.is_active else 'Inactive' }} +
+ {% if task.description %}

{{ task.description }}

{% endif %} +
+ {% if is_system_admin and can_edit %} + + Edit + + {% endif %} +
+
+ {% else %} +
No system default tasks configured yet.
+ {% endfor %}
+ + {% if current_selection and current_selection.is_enabled %} +
+
+
+

Firm Task Configuration

+

+ Firm Admin can edit, disable or enable tasks for this firm and add extra firm-only tasks. + System defaults are not changed. +

+
+ {% if can_manage_firm_tasks %} + + {% endif %} +
+ +
+ {% for task in current_templates %} +
+
+
+
+
{{ task.sequence_no }}. {{ task.task_name }}
+ + {{ 'Enabled for Firm' if task.is_active else 'Disabled for Firm' }} + +
+
+ Role: {{ task.default_role_name or '-' }} · + Mandatory: {{ 'Yes' if task.is_mandatory else 'No' }} · + Review: {{ 'Yes' if task.requires_review else 'No' }} +
+ {% if task.description %}

{{ task.description }}

{% endif %} +
+ + {% if can_manage_firm_tasks %} +
+ + Edit + +
+ + +
+
+ {% endif %} +
+
+ {% else %} +
+ No firm task templates are configured yet. Use Add / Manage Firm Tasks to copy defaults or add firm-specific tasks. +
+ {% endfor %} +
+ +
+ Editing or disabling a firm task affects future task generation only. Existing engagement task instances remain unchanged. +
+
+ {% endif %} {% endblock %} diff --git a/app/modules/services/templates/services/task_template_detail.html b/app/modules/services/templates/services/task_template_detail.html index cade5b2..8d11db8 100644 --- a/app/modules/services/templates/services/task_template_detail.html +++ b/app/modules/services/templates/services/task_template_detail.html @@ -186,7 +186,21 @@ {% endif %} - {% if can_manage_tasks %}Edit{% endif %} + {% if can_manage_tasks %} +
+ + Edit + +
+ + +
+
+ {% endif %} {% else %} diff --git a/app/modules/services/ui.py b/app/modules/services/ui.py index a3267b4..a8ffa68 100644 --- a/app/modules/services/ui.py +++ b/app/modules/services/ui.py @@ -602,6 +602,8 @@ def catalogue_detail(request: Request, catalogue_id: int): catalogue=row, can_edit=can_edit, can_manage_firm_services=_can_manage_firm_services(db, user), + can_manage_firm_tasks=_can_manage_firm_tasks(db, user), + is_system_admin=_is_system_admin(db, user), branches=branches, current_selection=get_firm_selection(db, tenant_id=tenant_id, catalogue_id=row.id), current_templates=get_firm_task_templates(db, tenant_id=tenant_id, catalogue_id=row.id), @@ -1548,6 +1550,58 @@ def firm_task_document_template_download(request: Request, template_id: int): db.close() +@router.post('/templates/{catalogue_id}/tasks/{task_id}/toggle-active') +def firm_task_template_toggle_active( + request: Request, + catalogue_id: int, + task_id: int, + csrf_token: str = Form(...), +): + """Enable/disable a firm task template without changing the system default. + + Existing engagement task instances are snapshots and are intentionally not + modified. This affects task generation for future engagements only. + """ + validate_csrf(request, csrf_token) + db = CommonSessionLocal() + try: + user = get_current_user(request, db=db) + if not user: + return RedirectResponse(url='/login', status_code=303) + + if not _can_manage_firm_tasks(db, user): + return _redirect_denied() + + tenant_id = _active_tenant_id(request, user) + selection = get_firm_selection(db, tenant_id=tenant_id, catalogue_id=catalogue_id) + if not selection or not selection.is_enabled: + return RedirectResponse(url='/services', status_code=303) + + task = get_firm_task_template( + db, + tenant_id=tenant_id, + catalogue_id=catalogue_id, + task_id=task_id, + ) + if not task: + return RedirectResponse( + url=f'/services/templates/{catalogue_id}?error=task_missing', + status_code=303, + ) + + task.is_active = not bool(task.is_active) + task.updated_by_user_id = user.id + db.commit() + + state = 'enabled' if task.is_active else 'disabled' + return RedirectResponse( + url=f'/services/templates/{catalogue_id}?task_{state}=1', + status_code=303, + ) + finally: + db.close() + + @router.get('/templates/{catalogue_id}/tasks/{task_id}/edit') def firm_task_template_edit_page(request: Request, catalogue_id: int, task_id: int): db = CommonSessionLocal()