Add phase 4 registration and renewal lifecycle management

This commit is contained in:
A R R R Associates
2026-07-23 12:05:41 +05:30
parent 0f7d6f4396
commit 929ed26737
14 changed files with 507 additions and 0 deletions
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
{% extends "ui/templates/base/layout.html" %}{% block content %}<div class="space-y-6"><div class="flex items-center justify-between"><div><h1 class="text-2xl font-semibold">Registrations & Renewals</h1><p class="text-sm text-slate-500">Expiry, periodic updates, generated renewal work and escalation.</p></div>{% if can_manage %}<div class="flex gap-2"><a href="/registrations/masters" class="rounded border px-3 py-2">Lifecycle Masters</a><form method="post" action="/registrations/run-engine"><input type="hidden" name="csrf_token" value="{{ csrf_token }}"><button class="rounded bg-brand-600 px-3 py-2 text-white">Run Lifecycle Engine</button></form></div>{% endif %}</div><div class="grid gap-4 md:grid-cols-4">{% for label,value in [('Active',counts.active),('Due / Update Due',counts.due),('Expired',counts.expired),('Open Renewal Tasks',counts.tasks)] %}<div class="rounded-xl border bg-white p-4"><div class="text-sm text-slate-500">{{ label }}</div><div class="text-3xl font-semibold">{{ value }}</div></div>{% endfor %}</div><div class="rounded-xl border bg-white"><div class="border-b p-4 font-semibold">Open renewal and update work</div><div class="overflow-x-auto"><table class="min-w-full text-sm"><thead><tr class="bg-slate-50"><th class="p-3 text-left">Due</th><th class="p-3 text-left">Client</th><th class="p-3 text-left">Work</th><th class="p-3 text-left">Status</th></tr></thead><tbody>{% for task,client in tasks %}<tr class="border-t"><td class="p-3">{{ task.cycle_due_date }}</td><td class="p-3">{{ client.client_name }}</td><td class="p-3"><a class="text-brand-600" href="/registrations/tasks/{{ task.id }}">{{ task.title }}</a></td><td class="p-3">{{ task.status|replace('_',' ')|title }}</td></tr>{% else %}<tr><td colspan="4" class="p-6 text-center text-slate-500">No open lifecycle work.</td></tr>{% endfor %}</tbody></table></div></div><div class="rounded-xl border bg-white"><div class="border-b p-4 font-semibold">Client registrations</div><div class="overflow-x-auto"><table class="min-w-full text-sm"><thead><tr class="bg-slate-50"><th class="p-3 text-left">Client</th><th class="p-3 text-left">Type</th><th class="p-3 text-left">Number</th><th class="p-3 text-left">Expiry / Next action</th><th class="p-3 text-left">Status</th></tr></thead><tbody>{% for reg,client,rt in registrations %}<tr class="border-t"><td class="p-3"><a class="text-brand-600" href="/registrations/clients/{{ client.id }}">{{ client.client_name }}</a></td><td class="p-3">{{ rt.name }}</td><td class="p-3">{{ reg.registration_number }}</td><td class="p-3">{{ reg.valid_until or reg.next_action_date or '—' }}</td><td class="p-3">{{ reg.status|replace('_',' ')|title }}</td></tr>{% else %}<tr><td colspan="5" class="p-6 text-center text-slate-500">No registration records.</td></tr>{% endfor %}</tbody></table></div></div></div>{% endblock %}
@@ -0,0 +1 @@
{% extends "ui/templates/base/layout.html" %}{% block content %}<div class="space-y-6"><div><h1 class="text-2xl font-semibold">Registration Lifecycle Masters</h1><a class="text-sm text-brand-600" href="/registrations">← Dashboard</a></div>{% if can_manage %}<div class="grid gap-4 lg:grid-cols-3"><form method="post" action="/registrations/masters/types" class="space-y-3 rounded-xl border bg-white p-4"><h2 class="font-semibold">Registration Type</h2><input type="hidden" name="csrf_token" value="{{csrf_token}}"><input class="w-full rounded border p-2" name="code" placeholder="Code" required><input class="w-full rounded border p-2" name="name" placeholder="Name" required><input class="w-full rounded border p-2" name="issuing_authority" placeholder="Issuing authority"><label class="block"><input type="checkbox" name="supports_expiry"> Expiry based</label><label class="block"><input type="checkbox" name="supports_related_person"> Person based</label><button class="rounded bg-brand-600 px-3 py-2 text-white">Save Type</button></form><form method="post" action="/registrations/masters/rules" class="space-y-3 rounded-xl border bg-white p-4"><h2 class="font-semibold">Lifecycle Rule</h2><input type="hidden" name="csrf_token" value="{{csrf_token}}"><select class="w-full rounded border p-2" name="registration_type_id">{% for x in types %}<option value="{{x.id}}">{{x.name}}</option>{% endfor %}</select><input class="w-full rounded border p-2" name="entity_type" placeholder="Entity type (blank = all)"><select class="w-full rounded border p-2" name="cycle_type"><option value="expiry_renewal">Expiry renewal</option><option value="annual_update">Annual update</option><option value="annual_confirmation">Annual confirmation</option><option value="periodic_revalidation">Periodic revalidation</option><option value="event_based_update">Event based update</option><option value="no_expiry">No expiry</option></select><input class="w-full rounded border p-2" name="frequency_months" type="number" placeholder="Frequency months"><input class="w-full rounded border p-2" name="renewal_window_days" type="number" value="60"><input class="w-full rounded border p-2" name="reminder_days_csv" value="90,60,30,15,7,0"><label><input type="checkbox" name="auto_create_task" checked> Auto-create renewal work</label><label class="block"><input type="checkbox" name="requires_client_approval"> Client approval</label><label class="block"><input type="checkbox" name="requires_partner_review"> Partner review</label><button class="rounded bg-brand-600 px-3 py-2 text-white">Save Rule</button></form><form method="post" action="/registrations/masters/documents" class="space-y-3 rounded-xl border bg-white p-4"><h2 class="font-semibold">Document Requirement</h2><input type="hidden" name="csrf_token" value="{{csrf_token}}"><select class="w-full rounded border p-2" name="registration_type_id">{% for x in types %}<option value="{{x.id}}">{{x.name}}</option>{% endfor %}</select><select class="w-full rounded border p-2" name="action_type"><option value="registration">Registration</option><option value="renewal" selected>Renewal</option><option value="update">Update</option></select><input class="w-full rounded border p-2" name="document_name" placeholder="Document name" required><textarea class="w-full rounded border p-2" name="description" placeholder="Description"></textarea><label><input type="checkbox" name="mandatory" checked> Mandatory</label><button class="rounded bg-brand-600 px-3 py-2 text-white">Save Requirement</button></form></div>{% endif %}<div class="grid gap-4 lg:grid-cols-2"><div class="rounded-xl border bg-white p-4"><h2 class="font-semibold">Types</h2>{% for x in types %}<div class="border-b py-2"><b>{{x.code}}</b> — {{x.name}}</div>{% endfor %}</div><div class="rounded-xl border bg-white p-4"><h2 class="font-semibold">Rules & document templates</h2>{% for r,t in rules %}<div class="border-b py-2">{{t.name}} — {{r.cycle_type|replace('_',' ')}} — {{r.renewal_window_days}} days</div>{% endfor %}{% for d,t in templates_rows %}<div class="border-b py-2">{{t.name}} / {{d.action_type}} — {{d.document_name}}</div>{% endfor %}</div></div></div>{% endblock %}
@@ -0,0 +1 @@
{% extends "ui/templates/base/layout.html" %}{% block content %}<div class="space-y-6"><div><h1 class="text-2xl font-semibold">{{task.title}}</h1><a class="text-sm text-brand-600" href="/registrations">← Dashboard</a></div><div class="grid gap-4 lg:grid-cols-3"><div class="rounded-xl border bg-white p-4"><h2 class="font-semibold">Lifecycle work</h2><dl class="mt-3 space-y-2 text-sm"><div><dt class="text-slate-500">Client</dt><dd>{{client.client_name}}</dd></div><div><dt class="text-slate-500">Registration</dt><dd>{{registration_type.name}} — {{registration.registration_number}}</dd></div><div><dt class="text-slate-500">Due</dt><dd>{{task.cycle_due_date}}</dd></div><div><dt class="text-slate-500">Status</dt><dd>{{task.status}}</dd></div></dl></div><div class="rounded-xl border bg-white p-4"><h2 class="font-semibold">Document checklist</h2>{% for d in documents %}<div class="border-b py-2">{{d.document_name}} {% if d.mandatory %}<span class="text-red-600">*</span>{% endif %} — {{d.status}}</div>{% else %}<p class="py-3 text-slate-500">No template requirements.</p>{% endfor %}</div><div class="rounded-xl border bg-white p-4"><h2 class="font-semibold">History</h2>{% for a in actions %}<div class="border-b py-2 text-sm">{{a.action_type|title}} · {{a.completion_date or a.created_at_utc.date()}} · {{a.acknowledgement_number or ''}}</div>{% else %}<p class="py-3 text-slate-500">No completed lifecycle actions.</p>{% endfor %}</div></div>{% if can_manage %}<div class="grid gap-4 lg:grid-cols-2"><form method="post" action="/registrations/tasks/{{task.id}}/status" class="space-y-3 rounded-xl border bg-white p-4"><h2 class="font-semibold">Update progress</h2><input type="hidden" name="csrf_token" value="{{csrf_token}}"><select class="w-full rounded border p-2" name="status"><option>pending</option><option>documents_pending</option><option>prepared</option><option>awaiting_client_approval</option><option>submitted</option><option>query_raised</option><option>under_review</option></select><input class="w-full rounded border p-2" type="date" name="submitted_on"><input class="w-full rounded border p-2" name="acknowledgement_number" placeholder="Acknowledgement number"><textarea class="w-full rounded border p-2" name="notes" placeholder="Notes"></textarea><button class="rounded bg-brand-600 px-3 py-2 text-white">Update</button></form><form method="post" action="/registrations/tasks/{{task.id}}/complete" class="space-y-3 rounded-xl border bg-white p-4"><h2 class="font-semibold">Complete and schedule next cycle</h2><input type="hidden" name="csrf_token" value="{{csrf_token}}"><label class="text-sm">New validity date</label><input class="w-full rounded border p-2" type="date" name="new_valid_until"><input class="w-full rounded border p-2" name="acknowledgement_number" placeholder="Acknowledgement / reference"><textarea class="w-full rounded border p-2" name="notes" placeholder="Completion notes"></textarea><button class="rounded bg-emerald-600 px-3 py-2 text-white">Complete Renewal / Update</button></form></div>{% endif %}</div>{% endblock %}