Integrate UDIN controls into final document workflow

This commit is contained in:
A R R R Associates
2026-07-06 18:05:00 +05:30
parent eb1cf6cbf2
commit 561de117e4
10 changed files with 723 additions and 10 deletions
@@ -8,6 +8,7 @@
</div>
<div class="flex flex-wrap gap-2">
<a href="/services/engagements/{{ engagement.id }}" class="rounded-xl border border-slate-300 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Engagement</a>
<a href="/documents/udin-register?financial_year={{ engagement.financial_year }}" class="rounded-xl border border-slate-300 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">UDIN Register</a>
<a href="/documents" class="rounded-xl border border-slate-300 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Back</a>
</div>
</div>
@@ -15,7 +16,10 @@
{% if request.query_params.get('uploaded') %}<div class="rounded-2xl border border-emerald-200 bg-emerald-50 p-4 text-sm text-emerald-800">Document uploaded successfully.</div>{% endif %}
{% if request.query_params.get('deleted') %}<div class="rounded-2xl border border-amber-200 bg-amber-50 p-4 text-sm text-amber-800">Document archived successfully.</div>{% endif %}
{% if request.query_params.get('download_queued') %}<div class="rounded-2xl border border-sky-200 bg-sky-50 p-4 text-sm text-sky-800">The file is stored in branch local storage. A secure retrieval request #{{ request.query_params.get('download_queued') }} has been queued. Please refresh after the local storage app fulfils it.</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 file size, permission and storage path.</div>{% endif %}
{% if request.query_params.get('udin_saved') %}<div class="rounded-2xl border border-emerald-200 bg-emerald-50 p-4 text-sm text-emerald-800">UDIN details saved successfully.</div>{% endif %}
{% if request.query_params.get('released') %}<div class="rounded-2xl border border-emerald-200 bg-emerald-50 p-4 text-sm text-emerald-800">Document released as final.</div>{% endif %}
{% if request.query_params.get('reopened') %}<div class="rounded-2xl border border-amber-200 bg-amber-50 p-4 text-sm text-amber-800">Final release reopened to draft.</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 file size, permission, UDIN, release status and storage path.</div>{% endif %}
{% if can_upload %}
<section class="rounded-2xl bg-white p-5 shadow-soft">
@@ -43,6 +47,13 @@
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">File</label>
<input type="file" name="file" required class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
</div>
<div class="md:col-span-2 rounded-xl border border-amber-200 bg-amber-50 p-3 text-sm text-amber-900">
<label class="inline-flex items-center gap-2 font-semibold">
<input type="checkbox" name="udin_required" value="1" class="rounded border-amber-300">
UDIN required before final release
</label>
<p class="mt-1 text-xs text-amber-800">Use this for certificate, audit report, signed output or other deliverable where partner UDIN is applicable.</p>
</div>
<div class="md:col-span-2">
<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"></textarea>
@@ -66,6 +77,7 @@
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Type</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Latest Version</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Storage</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">UDIN / Release</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Revision History</th>
<th class="px-4 py-3 text-right text-xs font-semibold uppercase tracking-wide text-slate-500">Action</th>
</tr>
@@ -83,13 +95,58 @@
<div class="mt-1 font-mono text-[11px] break-all">{{ latest.local_relative_path }}</div>
{% else %}-{% endif %}
</td>
<td class="px-4 py-3 text-xs text-slate-600">
<div><span class="rounded-full px-2 py-1 {{ 'bg-emerald-100 text-emerald-800' if doc.final_release_status == 'released' else 'bg-slate-100 text-slate-700' }}">{{ (doc.final_release_status or 'draft').replace('_',' ').title() }}</span></div>
<div class="mt-2">UDIN: <span class="font-semibold">{{ (doc.udin_status or 'not_required').replace('_',' ').title() }}</span></div>
{% if doc.udin_number %}<div class="font-mono text-[11px]">{{ doc.udin_number }}</div>{% endif %}
{% if doc.udin_date %}<div>Date: {{ doc.udin_date }}</div>{% endif %}
{% if doc.udin_required and not doc.udin_number %}<div class="mt-1 text-red-600">UDIN pending before final release.</div>{% endif %}
</td>
<td class="px-4 py-3 text-xs text-slate-600">
{% for v in doc.versions %}
<div><a href="/documents/versions/{{ v.id }}/download" class="text-brand-700 hover:underline">v{{ v.version_no }}</a> · {{ v.original_filename }}{% if v.remarks %} · {{ v.remarks }}{% endif %}</div>
{% endfor %}
</td>
<td class="px-4 py-3 text-right text-sm">
<td class="px-4 py-3 text-right text-sm align-top">
{% if latest %}<a href="/documents/{{ doc.id }}/download" class="font-medium text-brand-700 hover:underline">Download Latest</a>{% endif %}
{% if 'udin.manage' in current_user_permissions %}
<details class="mt-3 text-left">
<summary class="cursor-pointer text-sm font-semibold text-brand-700">UDIN / Release</summary>
<div class="mt-3 space-y-3 rounded-xl border border-slate-200 bg-slate-50 p-3">
<form method="post" action="/documents/{{ doc.id }}/udin" class="grid gap-2">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="hidden" name="redirect_to" value="/documents/engagements/{{ engagement.id }}">
<label class="inline-flex items-center gap-2 text-xs font-semibold text-slate-700"><input type="checkbox" name="udin_required" value="1" {% if doc.udin_required %}checked{% endif %}> UDIN required</label>
<input type="text" name="udin_number" value="{{ doc.udin_number or '' }}" placeholder="UDIN number" class="rounded-lg border border-slate-300 px-2 py-1 text-xs">
<div class="grid grid-cols-2 gap-2">
<input type="date" name="udin_date" value="{{ doc.udin_date or '' }}" class="rounded-lg border border-slate-300 px-2 py-1 text-xs">
<input type="date" name="udin_document_date" value="{{ doc.udin_document_date or '' }}" class="rounded-lg border border-slate-300 px-2 py-1 text-xs">
</div>
<input type="text" name="udin_document_type" value="{{ doc.udin_document_type or doc.document_type.replace('_',' ').title() }}" placeholder="Document type" class="rounded-lg border border-slate-300 px-2 py-1 text-xs">
<div class="grid grid-cols-2 gap-2">
<input type="text" name="udin_financial_year" value="{{ doc.udin_financial_year or doc.financial_year }}" placeholder="FY" class="rounded-lg border border-slate-300 px-2 py-1 text-xs">
<input type="text" name="udin_amount" value="{{ doc.udin_amount or '' }}" placeholder="Amount, if any" class="rounded-lg border border-slate-300 px-2 py-1 text-xs">
</div>
<input type="text" name="udin_notes" value="{{ doc.udin_notes or '' }}" placeholder="UDIN notes" class="rounded-lg border border-slate-300 px-2 py-1 text-xs">
<button class="rounded-lg bg-slate-800 px-3 py-1.5 text-xs font-semibold text-white">Save UDIN</button>
</form>
{% if doc.final_release_status != 'released' %}
<form method="post" action="/documents/{{ doc.id }}/final-release" onsubmit="return confirm('Release this document as final?');" class="grid gap-2">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="hidden" name="redirect_to" value="/documents/engagements/{{ engagement.id }}">
<input type="text" name="release_notes" placeholder="Release notes" class="rounded-lg border border-slate-300 px-2 py-1 text-xs">
<button class="rounded-lg bg-emerald-600 px-3 py-1.5 text-xs font-semibold text-white">Release Final</button>
</form>
{% else %}
<form method="post" action="/documents/{{ doc.id }}/reopen-final" onsubmit="return confirm('Reopen this final document to draft?');">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="hidden" name="redirect_to" value="/documents/engagements/{{ engagement.id }}">
<button class="rounded-lg border border-amber-300 px-3 py-1.5 text-xs font-semibold text-amber-700">Reopen Draft</button>
</form>
{% endif %}
</div>
</details>
{% endif %}
{% if can_upload %}
<form method="post" action="/documents/{{ doc.id }}/delete" class="ml-3 inline" onsubmit="return confirm('Archive this document?');">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
@@ -99,7 +156,7 @@
</td>
</tr>
{% else %}
<tr><td colspan="6" class="px-4 py-8 text-center text-sm text-slate-500">No documents uploaded for this engagement.</td></tr>
<tr><td colspan="7" class="px-4 py-8 text-center text-sm text-slate-500">No documents uploaded for this engagement.</td></tr>
{% endfor %}
</tbody>
</table>
@@ -17,7 +17,9 @@
</div>
{% if request.query_params.get('uploaded') %}<div class="rounded-2xl border border-emerald-200 bg-emerald-50 p-4 text-sm text-emerald-800">Task document 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">Upload failed. Please verify file, requirement and permission.</div>{% endif %}
{% if request.query_params.get('udin_saved') %}<div class="rounded-2xl border border-emerald-200 bg-emerald-50 p-4 text-sm text-emerald-800">UDIN details saved successfully.</div>{% endif %}
{% if request.query_params.get('released') %}<div class="rounded-2xl border border-emerald-200 bg-emerald-50 p-4 text-sm text-emerald-800">Document released as final.</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">Upload/action failed. Please verify file, requirement, UDIN and permission.</div>{% endif %}
<section class="grid gap-4 md:grid-cols-3">
<div class="rounded-2xl bg-white p-5 shadow-soft"><div class="text-xs uppercase tracking-wide text-slate-500">Mandatory Pending</div><div class="mt-2 text-2xl font-semibold text-slate-900">{{ requirement_status|selectattr('is_pending_mandatory')|list|length }}</div></div>
@@ -61,6 +63,13 @@
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">File</label>
<input type="file" name="file" required class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
</div>
<div class="md:col-span-2 rounded-xl border border-amber-200 bg-amber-50 p-3 text-sm text-amber-900">
<label class="inline-flex items-center gap-2 font-semibold">
<input type="checkbox" name="udin_required" value="1" class="rounded border-amber-300">
UDIN required before final release
</label>
<p class="mt-1 text-xs text-amber-800">Use this for final certificates, reports or signed outputs prepared from this task.</p>
</div>
<div>
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Revision Remarks</label>
<input type="text" name="remarks" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
@@ -95,12 +104,52 @@
<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">All Task Documents</h3></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 text-slate-500">Document</th><th class="px-4 py-3 text-left text-xs font-semibold uppercase text-slate-500">Latest Version</th><th class="px-4 py-3 text-right text-xs font-semibold uppercase text-slate-500">Action</th></tr></thead>
<thead class="bg-slate-50"><tr><th class="px-4 py-3 text-left text-xs font-semibold uppercase text-slate-500">Document</th><th class="px-4 py-3 text-left text-xs font-semibold uppercase text-slate-500">Latest Version</th><th class="px-4 py-3 text-left text-xs font-semibold uppercase text-slate-500">UDIN / Release</th><th class="px-4 py-3 text-right text-xs font-semibold uppercase text-slate-500">Action</th></tr></thead>
<tbody class="divide-y divide-slate-100">
{% for doc in documents %}
{% set latest = doc.versions[0] if doc.versions else None %}
<tr><td class="px-4 py-3 text-sm"><div class="font-medium text-slate-900">{{ doc.title }}</div><div class="text-xs text-slate-500">{{ doc.document_type.replace('_',' ').title() }}{% if doc.document_requirement %} · {{ doc.document_requirement.document_name }}{% endif %}</div></td><td class="px-4 py-3 text-xs text-slate-600">{% if latest %}v{{ latest.version_no }} · {{ latest.original_filename }}{% else %}-{% endif %}</td><td class="px-4 py-3 text-right text-sm">{% if latest %}<a href="/documents/{{ doc.id }}/download" class="text-brand-700 hover:underline">Download</a>{% endif %}</td></tr>
{% else %}<tr><td colspan="3" class="px-4 py-8 text-center text-sm text-slate-500">No task documents uploaded yet.</td></tr>{% endfor %}
<tr>
<td class="px-4 py-3 text-sm"><div class="font-medium text-slate-900">{{ doc.title }}</div><div class="text-xs text-slate-500">{{ doc.document_type.replace('_',' ').title() }}{% if doc.document_requirement %} · {{ doc.document_requirement.document_name }}{% endif %}</div></td>
<td class="px-4 py-3 text-xs text-slate-600">{% if latest %}v{{ latest.version_no }} · {{ latest.original_filename }}{% else %}-{% endif %}</td>
<td class="px-4 py-3 text-xs text-slate-600">
<div><span class="rounded-full px-2 py-1 {{ 'bg-emerald-100 text-emerald-800' if doc.final_release_status == 'released' else 'bg-slate-100 text-slate-700' }}">{{ (doc.final_release_status or 'draft').replace('_',' ').title() }}</span></div>
<div class="mt-2">UDIN: <span class="font-semibold">{{ (doc.udin_status or 'not_required').replace('_',' ').title() }}</span></div>
{% if doc.udin_number %}<div class="font-mono text-[11px]">{{ doc.udin_number }}</div>{% endif %}
{% if doc.udin_required and not doc.udin_number %}<div class="mt-1 text-red-600">UDIN pending before final release.</div>{% endif %}
</td>
<td class="px-4 py-3 text-right text-sm align-top">
{% if latest %}<a href="/documents/{{ doc.id }}/download" class="text-brand-700 hover:underline">Download</a>{% endif %}
{% if 'udin.manage' in current_user_permissions %}
<details class="mt-3 text-left">
<summary class="cursor-pointer text-sm font-semibold text-brand-700">UDIN / Release</summary>
<div class="mt-3 space-y-3 rounded-xl border border-slate-200 bg-slate-50 p-3">
<form method="post" action="/documents/{{ doc.id }}/udin" class="grid gap-2">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="hidden" name="redirect_to" value="/documents/tasks/{{ task.id }}">
<label class="inline-flex items-center gap-2 text-xs font-semibold text-slate-700"><input type="checkbox" name="udin_required" value="1" {% if doc.udin_required %}checked{% endif %}> UDIN required</label>
<input type="text" name="udin_number" value="{{ doc.udin_number or '' }}" placeholder="UDIN number" class="rounded-lg border border-slate-300 px-2 py-1 text-xs">
<div class="grid grid-cols-2 gap-2">
<input type="date" name="udin_date" value="{{ doc.udin_date or '' }}" class="rounded-lg border border-slate-300 px-2 py-1 text-xs">
<input type="date" name="udin_document_date" value="{{ doc.udin_document_date or '' }}" class="rounded-lg border border-slate-300 px-2 py-1 text-xs">
</div>
<input type="text" name="udin_document_type" value="{{ doc.udin_document_type or doc.document_type.replace('_',' ').title() }}" placeholder="Document type" class="rounded-lg border border-slate-300 px-2 py-1 text-xs">
<div class="grid grid-cols-2 gap-2"><input type="text" name="udin_financial_year" value="{{ doc.udin_financial_year or doc.financial_year }}" class="rounded-lg border border-slate-300 px-2 py-1 text-xs"><input type="text" name="udin_amount" value="{{ doc.udin_amount or '' }}" placeholder="Amount" class="rounded-lg border border-slate-300 px-2 py-1 text-xs"></div>
<input type="text" name="udin_notes" value="{{ doc.udin_notes or '' }}" placeholder="UDIN notes" class="rounded-lg border border-slate-300 px-2 py-1 text-xs">
<button class="rounded-lg bg-slate-800 px-3 py-1.5 text-xs font-semibold text-white">Save UDIN</button>
</form>
{% if doc.final_release_status != 'released' %}
<form method="post" action="/documents/{{ doc.id }}/final-release" onsubmit="return confirm('Release this document as final?');" class="grid gap-2">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}"><input type="hidden" name="redirect_to" value="/documents/tasks/{{ task.id }}">
<input type="text" name="release_notes" placeholder="Release notes" class="rounded-lg border border-slate-300 px-2 py-1 text-xs">
<button class="rounded-lg bg-emerald-600 px-3 py-1.5 text-xs font-semibold text-white">Release Final</button>
</form>
{% endif %}
</div>
</details>
{% endif %}
</td>
</tr>
{% else %}<tr><td colspan="4" class="px-4 py-8 text-center text-sm text-slate-500">No task documents uploaded yet.</td></tr>{% endfor %}
</tbody>
</table>
</section>
@@ -0,0 +1,74 @@
{% extends "ui/templates/base/layout.html" %}
{% block content %}
<div class="space-y-6">
<div class="flex flex-wrap items-center justify-between gap-3">
<div>
<h2 class="text-xl font-semibold text-slate-900">UDIN Register</h2>
<p class="text-sm text-slate-500">Auto-generated from final document workflow. No separate manual register is required.</p>
</div>
<a href="/documents" class="rounded-xl border border-slate-300 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Engagement Documents</a>
</div>
<form method="get" action="/documents/udin-register" class="grid gap-3 rounded-2xl bg-white p-4 shadow-soft md:grid-cols-4">
<div>
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Financial Year</label>
<input type="text" name="financial_year" value="{{ financial_year or '' }}" placeholder="2026-27" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
</div>
<div>
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">UDIN Status</label>
<select name="status" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
<option value="">All</option>
{% for st in ['pending','generated','not_required','cancelled'] %}
<option value="{{ st }}" {% if selected_status == st %}selected{% endif %}>{{ st.replace('_',' ').title() }}</option>
{% endfor %}
</select>
</div>
<div>
<label class="mb-1 block text-xs font-semibold uppercase tracking-wide text-slate-500">Search</label>
<input type="text" name="q" value="{{ q or '' }}" placeholder="UDIN / title / code" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm">
</div>
<div class="flex items-end">
<button class="w-full rounded-xl bg-brand-600 px-4 py-2 text-sm font-semibold text-white hover:bg-brand-700">Filter</button>
</div>
</form>
<section class="grid gap-4 md:grid-cols-4">
{% set pending_count = rows|selectattr('udin_status','equalto','pending')|list|length %}
{% set generated_count = rows|selectattr('udin_status','equalto','generated')|list|length %}
{% set released_count = rows|selectattr('final_release_status','equalto','released')|list|length %}
<div class="rounded-2xl bg-white p-5 shadow-soft"><div class="text-xs uppercase tracking-wide text-slate-500">Total Documents</div><div class="mt-2 text-2xl font-semibold text-slate-900">{{ rows|length }}</div></div>
<div class="rounded-2xl bg-white p-5 shadow-soft"><div class="text-xs uppercase tracking-wide text-slate-500">UDIN Pending</div><div class="mt-2 text-2xl font-semibold text-red-600">{{ pending_count }}</div></div>
<div class="rounded-2xl bg-white p-5 shadow-soft"><div class="text-xs uppercase tracking-wide text-slate-500">UDIN Generated</div><div class="mt-2 text-2xl font-semibold text-emerald-600">{{ generated_count }}</div></div>
<div class="rounded-2xl bg-white p-5 shadow-soft"><div class="text-xs uppercase tracking-wide text-slate-500">Final Released</div><div class="mt-2 text-2xl font-semibold text-brand-700">{{ released_count }}</div></div>
</section>
<div class="overflow-hidden rounded-2xl bg-white shadow-soft">
<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">Date / FY</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Client / Engagement</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Document</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">UDIN</th>
<th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Release</th>
<th class="px-4 py-3 text-right text-xs font-semibold uppercase tracking-wide text-slate-500">Action</th>
</tr>
</thead>
<tbody class="divide-y divide-slate-100">
{% for doc in rows %}
<tr>
<td class="px-4 py-3 text-sm text-slate-700"><div>{{ doc.udin_date or '-' }}</div><div class="text-xs text-slate-500">FY {{ doc.udin_financial_year or doc.financial_year }}</div></td>
<td class="px-4 py-3 text-sm"><div class="font-medium text-slate-900">{{ doc.client.client_name if doc.client else '-' }}</div><div class="text-xs text-slate-500">{{ doc.engagement.catalogue.service_name if doc.engagement and doc.engagement.catalogue else 'Engagement #' ~ doc.engagement_id }}</div></td>
<td class="px-4 py-3 text-sm"><div class="font-medium text-slate-900">{{ doc.title }}</div><div class="text-xs text-slate-500">{{ doc.document_code }} · {{ doc.document_type.replace('_',' ').title() }}</div></td>
<td class="px-4 py-3 text-sm"><div><span class="rounded-full px-2 py-1 text-xs {{ 'bg-emerald-100 text-emerald-800' if doc.udin_status == 'generated' else ('bg-red-100 text-red-800' if doc.udin_status == 'pending' else 'bg-slate-100 text-slate-700') }}">{{ (doc.udin_status or 'not_required').replace('_',' ').title() }}</span></div>{% if doc.udin_number %}<div class="mt-1 font-mono text-xs">{{ doc.udin_number }}</div>{% endif %}</td>
<td class="px-4 py-3 text-sm"><span class="rounded-full px-2 py-1 text-xs {{ 'bg-emerald-100 text-emerald-800' if doc.final_release_status == 'released' else 'bg-slate-100 text-slate-700' }}">{{ (doc.final_release_status or 'draft').replace('_',' ').title() }}</span>{% if doc.released_at_utc %}<div class="mt-1 text-xs text-slate-500">{{ doc.released_at_utc }}</div>{% endif %}</td>
<td class="px-4 py-3 text-right text-sm"><a href="/documents/engagements/{{ doc.engagement_id }}" class="font-medium text-brand-700 hover:underline">Open</a>{% set latest = doc.versions[0] if doc.versions else None %}{% if latest %}<a href="/documents/{{ doc.id }}/download" class="ml-3 font-medium text-brand-700 hover:underline">Download</a>{% endif %}</td>
</tr>
{% else %}
<tr><td colspan="6" class="px-4 py-8 text-center text-sm text-slate-500">No UDIN records found.</td></tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
{% endblock %}