336 lines
28 KiB
HTML
336 lines
28 KiB
HTML
{% extends "ui/templates/base/layout.html" %}
|
|
{% block content %}
|
|
<div class="space-y-6">
|
|
<div class="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
|
|
<div>
|
|
<h2 class="text-xl font-semibold text-slate-900">Firm Task Templates</h2>
|
|
<p class="mt-1 text-sm text-slate-500">
|
|
{{ service.service_code }} · {{ service.service_name }}
|
|
{% if selection and selection.default_branch_id %} · Default Branch ID {{ selection.default_branch_id }}{% endif %}
|
|
</p>
|
|
</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>
|
|
</div>
|
|
|
|
{% if request.query_params.get('requirement_added') %}<div class="rounded-2xl border border-emerald-200 bg-emerald-50 p-4 text-sm text-emerald-800">Document requirement added successfully.</div>{% endif %}
|
|
{% if request.query_params.get('template_uploaded') %}<div class="rounded-2xl border border-emerald-200 bg-emerald-50 p-4 text-sm text-emerald-800">Template file uploaded successfully.</div>{% endif %}
|
|
{% 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 request.query_params.get('system_upgraded') %}<div class="rounded-2xl border border-emerald-200 bg-emerald-50 p-4 text-sm text-emerald-800">System update applied to the firm task. Safe unstarted tasks in open engagements were refreshed automatically.</div>{% endif %}
|
|
{% if request.query_params.get('system_kept') %}<div class="rounded-2xl border border-blue-200 bg-blue-50 p-4 text-sm text-blue-800">Firm customization retained for this system revision. You will be prompted again when the system default changes in a later revision.</div>{% endif %}
|
|
{% if request.query_params.get('sync_success') %}<div class="rounded-2xl border border-emerald-200 bg-emerald-50 p-4 text-sm text-emerald-800">System defaults synchronized: {{ request.query_params.get('created','0') }} created, {{ request.query_params.get('updated','0') }} updated, {{ request.query_params.get('custom_updates','0') }} customized task(s) awaiting review.</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>
|
|
<div class="mt-2 text-lg font-semibold text-slate-900">{{ 'Enabled' if selection and selection.is_enabled else 'Not Enabled' }}</div>
|
|
<p class="mt-1 text-sm text-slate-500">Firm-level service selection controls whether these task templates are used.</p>
|
|
</div>
|
|
<div class="rounded-2xl bg-white p-5 shadow-soft">
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Firm Tasks</div>
|
|
<div class="mt-2 text-lg font-semibold text-slate-900">{{ task_templates|length }}</div>
|
|
<p class="mt-1 text-sm text-slate-500">Tasks customised for the active firm.</p>
|
|
</div>
|
|
<div class="rounded-2xl bg-white p-5 shadow-soft">
|
|
<div class="text-xs font-semibold uppercase tracking-wide text-slate-500">System Defaults</div>
|
|
<div class="mt-2 text-lg font-semibold text-slate-900">{{ default_tasks|length }}</div>
|
|
<p class="mt-1 text-sm text-slate-500">Inherited defaults stay synchronized automatically; customized tasks require Firm Admin approval before a later system update is applied.</p>
|
|
</div>
|
|
</section>
|
|
|
|
{% if can_manage_tasks %}
|
|
<section class="rounded-2xl bg-white p-5 shadow-soft">
|
|
<div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
|
|
<div>
|
|
<h3 class="text-sm font-semibold text-slate-900">Add Firm Task</h3>
|
|
<p class="text-sm text-slate-500">Create a task template for this firm and service.</p>
|
|
</div>
|
|
{% if default_tasks|length > 0 %}
|
|
<form method="post" action="/services/catalogue/{{ service.id }}/firm-tasks/sync-system-defaults">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
|
<button class="rounded-xl border border-brand-300 px-4 py-2 text-sm font-medium text-brand-700 hover:bg-brand-50" type="submit">Sync System Defaults</button>
|
|
</form>
|
|
{% endif %}
|
|
</div>
|
|
|
|
<form method="post" action="/services/templates/{{ service.id }}/tasks/new" class="mt-5 grid gap-4 lg:grid-cols-12">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
|
<div class="lg:col-span-4">
|
|
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Task Name</label>
|
|
<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 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>
|
|
<input name="sequence_no" type="number" min="1" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" placeholder="Auto">
|
|
</div>
|
|
<div class="lg:col-span-3">
|
|
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Task Category <span class="font-normal normal-case text-slate-400">(optional)</span></label>
|
|
<select name="task_category" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
|
|
<option value="">Uncategorised / General Workflow</option>
|
|
{% 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">
|
|
<label class="inline-flex items-center gap-1"><input type="checkbox" name="is_mandatory" checked> Mandatory</label>
|
|
<label class="inline-flex items-center gap-1"><input type="checkbox" name="requires_review"> Review</label><label class="inline-flex items-center gap-1">Normal reviewer <select name="normal_review_role" class="rounded border border-slate-300 px-1 py-0.5"><option value="manager">Manager</option><option value="partner">Partner</option><option value="manager_or_partner">Manager / Partner</option></select></label>
|
|
<label class="inline-flex items-center gap-1"><input type="checkbox" name="is_active" checked> Active</label>
|
|
</div>
|
|
</div>
|
|
<div class="lg:col-span-12 rounded-2xl border border-indigo-200 bg-indigo-50 p-4">
|
|
<div class="text-sm font-semibold text-indigo-950">AQMM / Quality Control Tagging</div>
|
|
<p class="mt-1 text-xs text-indigo-800">Tick only the service checklist tasks that should form part of assurance engagement quality evidence.</p>
|
|
<div class="mt-3 grid gap-2 md:grid-cols-4 text-xs text-slate-700">
|
|
<label class="inline-flex items-center gap-1"><input type="checkbox" name="is_aqmm_task"> Part of AQMM</label>
|
|
<label class="inline-flex items-center gap-1"><input type="checkbox" name="aqmm_mandatory"> Mandatory</label>
|
|
<label class="inline-flex items-center gap-1"><input type="checkbox" name="aqmm_evidence_required"> Evidence required</label>
|
|
<label class="inline-flex items-center gap-1"><input type="checkbox" name="aqmm_manager_review_required"> Manager review</label>
|
|
<label class="inline-flex items-center gap-1"><input type="checkbox" name="aqmm_partner_review_required"> Partner review</label>
|
|
<label class="inline-flex items-center gap-1"><input type="checkbox" name="aqmm_review_partner_required"> Review partner review</label>
|
|
<label class="inline-flex items-center gap-1"><input type="checkbox" name="aqmm_blocks_final_release"> Blocks final release</label>
|
|
<input name="aqmm_reference" placeholder="AQMM reference / clause" class="rounded-lg border border-indigo-200 px-2 py-1 text-xs">
|
|
</div>
|
|
</div>
|
|
<div class="lg:col-span-10">
|
|
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Description</label>
|
|
<textarea name="description" rows="2" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" placeholder="Optional instructions for staff or reviewer"></textarea>
|
|
</div>
|
|
<div class="flex items-end lg:col-span-2">
|
|
<button class="w-full rounded-xl bg-brand-600 px-4 py-2 text-sm font-medium text-white hover:bg-brand-700" type="submit">Add Task</button>
|
|
</div>
|
|
</form>
|
|
</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>
|
|
<p class="text-sm text-slate-500">These tasks will be used when work is generated for this firm.</p>
|
|
</div>
|
|
<table class="min-w-full divide-y divide-slate-200">
|
|
<thead class="bg-slate-50">
|
|
<tr>
|
|
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Seq</th>
|
|
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Task</th>
|
|
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Role</th>
|
|
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Flags</th>
|
|
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Document Requirements</th>
|
|
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Template Uploads</th>
|
|
<th class="px-4 py-3"></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody class="divide-y divide-slate-100">
|
|
{% for task in task_templates %}
|
|
<tr>
|
|
<td class="px-4 py-3 text-sm font-medium text-slate-900 align-top">
|
|
<div class="flex items-center gap-2">
|
|
<span class="min-w-6">{{ task.sequence_no }}</span>
|
|
{% if can_manage_tasks %}
|
|
<div class="flex flex-col gap-1">
|
|
<form method="post" action="/services/templates/{{ service.id }}/tasks/{{ task.id }}/move">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
|
<input type="hidden" name="direction" value="up">
|
|
<button type="submit" title="Move task up" aria-label="Move task up"
|
|
class="h-6 w-7 rounded border border-slate-300 bg-white text-xs font-bold text-slate-600 hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-30"
|
|
{% if loop.first %}disabled{% endif %}>↑</button>
|
|
</form>
|
|
<form method="post" action="/services/templates/{{ service.id }}/tasks/{{ task.id }}/move">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
|
<input type="hidden" name="direction" value="down">
|
|
<button type="submit" title="Move task down" aria-label="Move task down"
|
|
class="h-6 w-7 rounded border border-slate-300 bg-white text-xs font-bold text-slate-600 hover:bg-slate-50 disabled:cursor-not-allowed disabled:opacity-30"
|
|
{% if loop.last %}disabled{% endif %}>↓</button>
|
|
</form>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
</td>
|
|
<td class="px-4 py-3 text-sm text-slate-700">
|
|
<div class="font-medium text-slate-900">{{ task.task_name }}</div>
|
|
<div class="mt-1 flex flex-wrap gap-1">
|
|
{% if task.source_system_task_id %}
|
|
{% if task.is_customized %}<span class="rounded-full bg-amber-50 px-2 py-0.5 text-[10px] font-semibold text-amber-700">Customized</span>{% else %}<span class="rounded-full bg-emerald-50 px-2 py-0.5 text-[10px] font-semibold text-emerald-700">System inherited</span>{% endif %}
|
|
{% else %}
|
|
<span class="rounded-full bg-slate-100 px-2 py-0.5 text-[10px] font-semibold text-slate-600">Firm-only</span>
|
|
{% endif %}
|
|
{% if task.system_update_available %}<span class="rounded-full bg-violet-100 px-2 py-0.5 text-[10px] font-semibold text-violet-800">System update available</span>{% endif %}
|
|
</div>
|
|
{% if task.system_update_available %}
|
|
{% set changes = system_update_diff_map.get(task.id, []) if system_update_diff_map else [] %}
|
|
<div class="mt-2 rounded-xl border border-violet-200 bg-violet-50 p-3 text-xs text-violet-950">
|
|
<div class="font-semibold">A newer system default is available. Your firm customization has not been overwritten.</div>
|
|
{% if changes %}
|
|
<div class="mt-2 space-y-1">
|
|
{% for change in changes[:5] %}
|
|
<div><span class="font-medium">{{ change.label }}:</span> {{ change.firm if change.firm is not none else '-' }} → {{ change.system if change.system is not none else '-' }}</div>
|
|
{% endfor %}
|
|
{% if changes|length > 5 %}<div class="text-violet-700">+ {{ changes|length - 5 }} more change(s)</div>{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
{% if can_manage_tasks %}
|
|
<div class="mt-3 flex flex-wrap gap-2">
|
|
<form method="post" action="/services/templates/{{ service.id }}/tasks/{{ task.id }}/system-update/upgrade" onsubmit="return confirm('Upgrade this customized firm task to the latest system default? Safe unstarted tasks in open engagements will also be refreshed.');">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
|
<button class="rounded-lg bg-violet-700 px-3 py-1.5 text-[11px] font-semibold text-white hover:bg-violet-800">Upgrade to System</button>
|
|
</form>
|
|
<form method="post" action="/services/templates/{{ service.id }}/tasks/{{ task.id }}/system-update/keep-firm">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
|
<button class="rounded-lg border border-violet-300 bg-white px-3 py-1.5 text-[11px] font-semibold text-violet-800 hover:bg-violet-100">Keep Firm Version</button>
|
|
</form>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
{% if task.task_category %}<div class="mt-1 text-[11px] font-semibold uppercase tracking-wide text-brand-600">Category: {{ task.task_category }}</div>{% endif %}
|
|
{% 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"><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_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 %}
|
|
{% if task.aqmm_mandatory %}<span class="rounded-full bg-rose-100 px-2 py-1 text-rose-800">AQMM Mandatory</span>{% endif %}
|
|
{% if task.aqmm_evidence_required %}<span class="rounded-full bg-sky-100 px-2 py-1 text-sky-800">Evidence</span>{% endif %}
|
|
{% if task.aqmm_blocks_final_release %}<span class="rounded-full bg-purple-100 px-2 py-1 text-purple-800">Final Gate</span>{% endif %}
|
|
<span class="rounded-full px-2 py-1 {{ 'bg-emerald-100 text-emerald-800' if task.is_active else 'bg-slate-100 text-slate-500' }}">{{ 'Active' if task.is_active else 'Inactive' }}</span>
|
|
</div>
|
|
</td>
|
|
<td class="px-4 py-3 text-xs text-slate-600 align-top">
|
|
{% set reqs = task_requirement_map.get(task.id, []) if task_requirement_map else [] %}
|
|
<div class="space-y-2">
|
|
{% for req in reqs %}
|
|
<div class="rounded-lg border border-slate-200 p-2">
|
|
<div class="font-medium text-slate-800">{{ req.document_name }}</div>
|
|
<div class="text-[11px] text-slate-500">{{ req.document_type.replace('_',' ').title() }} · {{ 'Mandatory' if req.is_mandatory else 'Optional' }} · {{ 'Active' if req.is_active else 'Inactive' }}</div>
|
|
{% if can_manage_tasks %}
|
|
<form method="post" action="/services/templates/{{ service.id }}/tasks/{{ task.id }}/document-requirements/{{ req.id }}/toggle" class="mt-1">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
|
<button class="text-[11px] font-semibold text-brand-700">{{ 'Deactivate' if req.is_active else 'Activate' }}</button>
|
|
</form>
|
|
{% endif %}
|
|
</div>
|
|
{% else %}<span class="text-slate-400">No requirements</span>{% endfor %}
|
|
</div>
|
|
{% if can_manage_tasks %}
|
|
<form method="post" action="/services/templates/{{ service.id }}/tasks/{{ task.id }}/document-requirements/new" class="mt-3 space-y-2 rounded-xl bg-slate-50 p-3">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
|
<input name="document_name" required placeholder="Document name" class="w-full rounded-lg border border-slate-300 px-2 py-1 text-xs">
|
|
<div class="grid grid-cols-2 gap-2">
|
|
<input name="document_type" value="GENERAL" placeholder="Type" class="rounded-lg border border-slate-300 px-2 py-1 text-xs">
|
|
<input name="sort_order" type="number" value="100" class="rounded-lg border border-slate-300 px-2 py-1 text-xs">
|
|
</div>
|
|
<input name="allowed_file_types" placeholder="Allowed: pdf,docx,xlsx" class="w-full rounded-lg border border-slate-300 px-2 py-1 text-xs">
|
|
<textarea name="instructions" rows="2" placeholder="Instructions" class="w-full rounded-lg border border-slate-300 px-2 py-1 text-xs"></textarea>
|
|
<label class="inline-flex items-center gap-1 text-[11px]"><input type="checkbox" name="is_mandatory" checked> Mandatory</label>
|
|
<button class="block rounded-lg bg-slate-900 px-3 py-1 text-xs font-semibold text-white">Add Requirement</button>
|
|
</form>
|
|
{% endif %}
|
|
</td>
|
|
<td class="px-4 py-3 text-xs text-slate-600 align-top">
|
|
{% set files = task_template_file_map.get(task.id, []) if task_template_file_map else [] %}
|
|
<div class="space-y-1">
|
|
{% for tpl in files %}
|
|
<div><a href="/services/document-templates/{{ tpl.id }}/download" class="font-medium text-brand-700 hover:underline">{{ tpl.template_name }}</a><div class="text-[11px] text-slate-500">{{ tpl.template_category or 'Template' }} · {{ tpl.original_filename }}</div></div>
|
|
{% else %}<span class="text-slate-400">No template files</span>{% endfor %}
|
|
</div>
|
|
{% if can_manage_tasks %}
|
|
<form method="post" action="/services/templates/{{ service.id }}/tasks/{{ task.id }}/document-templates/upload" enctype="multipart/form-data" class="mt-3 space-y-2 rounded-xl bg-slate-50 p-3">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
|
<input name="template_name" placeholder="Template name" class="w-full rounded-lg border border-slate-300 px-2 py-1 text-xs">
|
|
<input name="template_category" placeholder="NOC / Agreement / Deed" class="w-full rounded-lg border border-slate-300 px-2 py-1 text-xs">
|
|
<input type="file" name="file" required class="w-full rounded-lg border border-slate-300 px-2 py-1 text-xs">
|
|
<textarea name="description" rows="2" placeholder="Description" class="w-full rounded-lg border border-slate-300 px-2 py-1 text-xs"></textarea>
|
|
<button class="block rounded-lg bg-brand-600 px-3 py-1 text-xs font-semibold text-white">Upload Template</button>
|
|
</form>
|
|
{% endif %}
|
|
</td>
|
|
<td class="px-4 py-3 text-right align-top">
|
|
{% if can_manage_tasks %}
|
|
<div class="flex flex-col items-end gap-2">
|
|
<a href="/services/templates/{{ service.id }}/tasks/{{ task.id }}/edit"
|
|
class="rounded-lg border border-brand-200 bg-brand-50 px-3 py-1.5 text-xs font-semibold text-brand-700 hover:bg-brand-100">
|
|
Edit
|
|
</a>
|
|
<form method="post" action="/services/templates/{{ service.id }}/tasks/{{ task.id }}/toggle-active">
|
|
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
|
|
<button type="submit"
|
|
class="rounded-lg border px-3 py-1.5 text-xs font-semibold {% if task.is_active %}border-amber-300 bg-amber-50 text-amber-700 hover:bg-amber-100{% else %}border-emerald-300 bg-emerald-50 text-emerald-700 hover:bg-emerald-100{% endif %}">
|
|
{{ 'Disable for Firm' if task.is_active else 'Enable for Firm' }}
|
|
</button>
|
|
</form>
|
|
</div>
|
|
{% endif %}
|
|
</td>
|
|
</tr>
|
|
{% else %}
|
|
<tr><td colspan="7" class="px-4 py-8 text-center text-sm text-slate-500">No firm task templates yet. Copy defaults or add tasks manually.</td></tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</section>
|
|
</div>
|
|
{% endblock %}
|