Add task role eligibility and safe open engagement sync
This commit is contained in:
@@ -18,8 +18,28 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="mb-2 block text-sm font-medium text-slate-700">Default Role</label>
|
||||
<input type="text" name="default_role_name" value="{{ task.default_role_name or '' }}" class="w-full rounded-xl border border-slate-300 px-4 py-2 text-sm">
|
||||
<label class="mb-2 block text-sm font-medium text-slate-700">Default Assignee Role</label>
|
||||
<select name="default_role_name" class="w-full rounded-xl border border-slate-300 px-4 py-2 text-sm">
|
||||
<option value="">Automatic / existing fallback</option>
|
||||
{% for role in task_execution_roles %}
|
||||
<option value="{{ role }}" {% if (task.default_role_name or '') == role %}selected{% endif %}>{{ role }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<p class="mt-1 text-xs text-slate-500">This role receives the task first. If unavailable, another eligible role can be used.</p>
|
||||
</div>
|
||||
|
||||
<div class="md:col-span-2 rounded-xl border border-blue-200 bg-blue-50 p-4">
|
||||
<div class="text-sm font-semibold text-blue-950">Eligible Roles</div>
|
||||
<p class="mt-1 text-xs text-blue-800">Select every role allowed to perform this task. For Manager or Partner, select both.</p>
|
||||
{% set eligible_text = task.eligible_role_names or task.default_role_name or '' %}
|
||||
<div class="mt-3 flex flex-wrap gap-5 text-sm text-slate-700">
|
||||
{% for role in task_execution_roles %}
|
||||
<label class="inline-flex items-center gap-2">
|
||||
<input type="checkbox" name="eligible_roles" value="{{ role }}" {% if role in eligible_text.split(',') or role == task.default_role_name %}checked{% endif %}>
|
||||
{{ role }}
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
@@ -18,8 +18,28 @@
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label class="mb-2 block text-sm font-medium text-slate-700">Default Role</label>
|
||||
<input type="text" name="default_role_name" value="{{ task.default_role_name or '' }}" class="w-full rounded-xl border border-slate-300 px-4 py-2 text-sm">
|
||||
<label class="mb-2 block text-sm font-medium text-slate-700">Default Assignee Role</label>
|
||||
<select name="default_role_name" class="w-full rounded-xl border border-slate-300 px-4 py-2 text-sm">
|
||||
<option value="">Automatic / existing fallback</option>
|
||||
{% for role in task_execution_roles %}
|
||||
<option value="{{ role }}" {% if (task.default_role_name or '') == role %}selected{% endif %}>{{ role }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
<p class="mt-1 text-xs text-slate-500">This role receives the task first. If unavailable, another eligible role can be used.</p>
|
||||
</div>
|
||||
|
||||
<div class="md:col-span-2 rounded-xl border border-blue-200 bg-blue-50 p-4">
|
||||
<div class="text-sm font-semibold text-blue-950">Eligible Roles</div>
|
||||
<p class="mt-1 text-xs text-blue-800">Select every role allowed to perform this task. For Manager or Partner, select both.</p>
|
||||
{% set eligible_text = task.eligible_role_names or task.default_role_name or '' %}
|
||||
<div class="mt-3 flex flex-wrap gap-5 text-sm text-slate-700">
|
||||
{% for role in task_execution_roles %}
|
||||
<label class="inline-flex items-center gap-2">
|
||||
<input type="checkbox" name="eligible_roles" value="{{ role }}" {% if role in eligible_text.split(',') or role == task.default_role_name %}checked{% endif %}>
|
||||
{{ role }}
|
||||
</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
@@ -89,6 +109,15 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="md:col-span-2 rounded-xl border border-violet-200 bg-violet-50 p-4">
|
||||
<div class="text-sm font-semibold text-violet-950">Existing Open Engagements</div>
|
||||
<p class="mt-1 text-xs text-violet-800">Optional. Add missing tasks and refresh pending/not-started task role/assignee from the current firm template. Completed/history stays unchanged.</p>
|
||||
<div class="mt-3 space-y-2 text-sm text-slate-700">
|
||||
<label class="flex items-start gap-2"><input type="checkbox" name="sync_open_engagements" class="mt-1"><span><strong>Sync open engagements after Save</strong></span></label>
|
||||
<label class="flex items-start gap-2"><input type="checkbox" name="sync_started_open_tasks" class="mt-1"><span><strong>Also update assignee for In Progress / Blocked tasks</strong> without changing status, evidence, comments or history.</span></label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="md:col-span-2 rounded-xl border border-amber-200 bg-amber-50 p-4 text-sm text-amber-800">
|
||||
To deactivate this task, untick <strong>Active</strong> and save. No hard delete is used.
|
||||
</div>
|
||||
|
||||
@@ -59,8 +59,19 @@
|
||||
<input name="task_name" required class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" placeholder="e.g. Verify books with GSTR-2B">
|
||||
</div>
|
||||
<div class="lg:col-span-3">
|
||||
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Default Role</label>
|
||||
<input name="default_role_name" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" placeholder="Staff / Manager / Partner">
|
||||
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Default Assignee Role</label>
|
||||
<select name="default_role_name" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
|
||||
<option value="">Automatic</option>
|
||||
{% for role in task_execution_roles %}<option value="{{ role }}">{{ role }}</option>{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="lg:col-span-12 rounded-xl border border-blue-200 bg-blue-50 p-3">
|
||||
<div class="text-xs font-semibold uppercase tracking-wide text-blue-800">Eligible Roles</div>
|
||||
<div class="mt-2 flex flex-wrap gap-4 text-xs text-slate-700">
|
||||
{% for role in task_execution_roles %}
|
||||
<label class="inline-flex items-center gap-1"><input type="checkbox" name="eligible_roles" value="{{ role }}"> {{ role }}</label>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="lg:col-span-2">
|
||||
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Sequence</label>
|
||||
@@ -99,6 +110,32 @@
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
{% if request.query_params.get('synced') %}
|
||||
<div class="rounded-xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-800">
|
||||
Open engagement sync completed:
|
||||
{{ request.query_params.get('created', '0') }} missing task(s) added,
|
||||
{{ request.query_params.get('updated_pending', '0') }} pending task(s) refreshed,
|
||||
{{ request.query_params.get('updated_started', '0') }} started task assignee(s) refreshed,
|
||||
{{ request.query_params.get('preserved', '0') }} historical/unsafe task(s) preserved.
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if can_manage_tasks %}
|
||||
<section class="rounded-2xl border border-violet-200 bg-violet-50 p-4">
|
||||
<div class="flex flex-wrap items-start justify-between gap-3">
|
||||
<div>
|
||||
<h3 class="text-sm font-semibold text-violet-950">Sync Firm Tasks to Open Engagements</h3>
|
||||
<p class="mt-1 text-xs text-violet-800">Adds missing active tasks and refreshes pending/not-started role and assignee. Completed tasks, evidence, comments, review history and locked engagements are preserved.</p>
|
||||
</div>
|
||||
<form method="post" action="/services/templates/{{ service.id }}/sync-open-engagements" class="flex flex-wrap items-center gap-3" onsubmit="return confirm('Sync current firm task templates to open engagements?');">
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
||||
<label class="inline-flex items-center gap-2 text-xs text-violet-900"><input type="checkbox" name="include_started_open_tasks"> Also reassign In Progress / Blocked</label>
|
||||
<button type="submit" class="rounded-xl bg-violet-600 px-4 py-2 text-sm font-semibold text-white hover:bg-violet-700">Sync Open Engagements</button>
|
||||
</form>
|
||||
</div>
|
||||
</section>
|
||||
{% endif %}
|
||||
|
||||
<section class="overflow-hidden rounded-2xl bg-white shadow-soft">
|
||||
<div class="border-b border-slate-100 px-5 py-4">
|
||||
<h3 class="text-sm font-semibold text-slate-900">Firm Task List</h3>
|
||||
@@ -124,7 +161,7 @@
|
||||
<div class="font-medium text-slate-900">{{ task.task_name }}</div>
|
||||
{% if task.description %}<div class="mt-1 text-xs text-slate-500">{{ task.description }}</div>{% endif %}
|
||||
</td>
|
||||
<td class="px-4 py-3 text-sm text-slate-700">{{ task.default_role_name or '-' }}</td>
|
||||
<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.is_mandatory %}<span class="rounded-full bg-slate-100 px-2 py-1">Mandatory</span>{% endif %}
|
||||
|
||||
Reference in New Issue
Block a user