Add task administration upgrade with duplicate merge and task tools

This commit is contained in:
A R R R Associates
2026-08-30 22:12:27 +05:30
parent ad0815c807
commit af4f6e8b28
17 changed files with 2072 additions and 14 deletions
@@ -11,6 +11,8 @@
</div>
<div class="flex flex-wrap gap-2">
<a href="/services/templates" class="rounded-xl border border-slate-300 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Back to Templates</a>
<a href="/services/templates/{{ service.id }}/export" class="rounded-xl border border-emerald-300 bg-emerald-50 px-4 py-2 text-sm font-medium text-emerald-800 hover:bg-emerald-100">Export Tasks</a>
<a href="/services/templates/{{ service.id }}/duplicates" class="rounded-xl border border-amber-300 bg-amber-50 px-4 py-2 text-sm font-medium text-amber-800 hover:bg-amber-100">Duplicate Review</a>
<a href="/services/templates/{{ service.id }}/categories" class="rounded-xl border border-slate-300 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Task Categories</a>
<a href="/services/catalogue/{{ service.id }}" class="rounded-xl border border-brand-300 px-4 py-2 text-sm font-medium text-brand-700 hover:bg-brand-50">View Catalogue</a>
</div>
@@ -21,7 +23,15 @@
{% if request.query_params.get('error') %}<div class="rounded-2xl border border-red-200 bg-red-50 p-4 text-sm text-red-800">Action failed. Please check the selected task, file and permissions.</div>{% endif %}
{% if request.query_params.get('moved') %}<div class="rounded-2xl border border-emerald-200 bg-emerald-50 p-4 text-sm text-emerald-800">Task sequence updated. Use Sync Firm Tasks to Open Engagements if you want safe pending/open task snapshots refreshed.</div>{% endif %}
{% if request.query_params.get('move_error') %}<div class="rounded-2xl border border-red-200 bg-red-50 p-4 text-sm text-red-800">Task could not be moved.</div>{% endif %}
{% if request.query_params.get('imported') %}<div class="rounded-2xl border border-emerald-200 bg-emerald-50 p-4 text-sm text-emerald-800">Excel import completed: {{ request.query_params.get('created','0') }} created, {{ request.query_params.get('updated','0') }} updated.</div>{% endif %}
{% if request.query_params.get('import_error') %}<div class="rounded-2xl border border-red-200 bg-red-50 p-4 text-sm text-red-800">Excel import failed validation. No partial update was committed.</div>{% endif %}
{% if can_manage_tasks %}
<section class="rounded-2xl border border-emerald-200 bg-emerald-50 p-4">
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between"><div><h3 class="text-sm font-semibold text-emerald-950">Export · Edit · Re-import Firm Tasks</h3><p class="mt-1 text-xs text-emerald-800">Use the exported workbook for this service. Re-import updates by service code + sequence number and preserves all other ERP features.</p></div><form method="post" action="/services/templates/{{ service.id }}/import" enctype="multipart/form-data" class="flex flex-wrap items-center gap-2"><input type="hidden" name="csrf_token" value="{{ csrf_token }}"><input type="file" name="file" accept=".xlsx" required class="max-w-xs rounded-xl border border-emerald-200 bg-white px-3 py-2 text-xs"><button class="rounded-xl bg-emerald-700 px-4 py-2 text-sm font-semibold text-white hover:bg-emerald-800">Import Updated Excel</button></form></div>
</section>
{% endif %}
<section class="grid gap-4 md:grid-cols-3">
<div class="rounded-2xl bg-white p-5 shadow-soft">
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Firm Status</div>
@@ -87,6 +97,10 @@
{% for category in task_categories or [] %}{% if category.is_active %}<option value="{{ category.name }}">{{ category.name }}</option>{% endif %}{% endfor %}
</select>
</div>
<div class="lg:col-span-3">
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Task Tool</label>
<select name="task_tool_code" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">{% for tool in task_tools %}<option value="{{ tool.code }}">{{ tool.name }}</option>{% endfor %}</select>
</div>
<div class="lg:col-span-3">
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Options</label>
<div class="flex flex-wrap gap-3 rounded-xl border border-slate-200 px-3 py-2 text-xs text-slate-700">
@@ -197,7 +211,7 @@
<td class="px-4 py-3 text-sm text-slate-700"><div>{{ task.default_role_name or '-' }}</div><div class="mt-1 text-xs text-slate-500">Eligible: {{ task.eligible_role_names or task.default_role_name or '-' }}</div></td>
<td class="px-4 py-3 text-xs text-slate-600">
<div class="flex flex-wrap gap-1">
{% if task.task_category %}<span class="rounded-full bg-blue-50 px-2 py-1 text-blue-700">{{ task.task_category }}</span>{% endif %}
{% if task.task_category %}<span class="rounded-full bg-blue-50 px-2 py-1 text-blue-700">{{ task.task_category }}</span>{% endif %}{% if task.task_tool_code and task.task_tool_code != "NONE" %}<span class="rounded-full bg-violet-50 px-2 py-1 text-violet-700">Tool: {{ task.task_tool_code|replace("_"," ")|title }}</span>{% endif %}
{% if task.is_mandatory %}<span class="rounded-full bg-slate-100 px-2 py-1">Mandatory</span>{% endif %}
{% if task.requires_review %}<span class="rounded-full bg-amber-100 px-2 py-1 text-amber-800">Review: {{ (task.normal_review_role or "manager").replace("_"," ").title() }}</span>{% endif %}
{% if task.is_aqmm_task %}<span class="rounded-full bg-indigo-100 px-2 py-1 text-indigo-800">AQMM</span>{% endif %}