Add client groups and family tracking

This commit is contained in:
A R R R Associates
2026-07-25 22:32:35 +05:30
parent 5e6584702c
commit 2dc2a712e8
21 changed files with 444 additions and 161 deletions
@@ -60,7 +60,8 @@
</div>
{% endif %}
<div class="grid gap-6 xl:grid-cols-3">
<div class="rounded-2xl border border-slate-200 bg-white p-5 shadow-soft"><div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Client Group</div>{% if client_group %}<div class="mt-2 text-lg font-semibold text-slate-900"><a class="text-brand-700 hover:underline" href="/client-groups/{{ client_group.id }}">{{ client_group.group_name }}</a></div><div class="mt-1 text-sm text-slate-500">{{ client_group.group_code }} · {{ row.group_relationship or client_group.group_type }}{% if row.is_group_head %} · Group Head{% endif %}</div>{% else %}<div class="mt-2 text-sm text-slate-500">Not linked to a group.</div>{% endif %}</div>
<div class="grid gap-6 xl:grid-cols-3">
<section class="rounded-2xl bg-white p-6 shadow-soft xl:col-span-2">
<h3 class="text-base font-semibold text-slate-900">Profile</h3>
<div class="mt-4 grid gap-4 md:grid-cols-2">
@@ -7,7 +7,7 @@
<p class="text-sm text-slate-500">Association-aware list view.</p>
</div>
<div class="flex gap-3">
<div class="flex gap-3"><a href="/client-groups" class="inline-flex rounded-xl border border-slate-300 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">Client Groups</a>
{% if can_export %}
<a href="/clients/export?q={{ q }}&status={{ status }}&client_type={{ client_type }}&include_archived={{ include_archived }}&sort_by={{ sort_by }}&sort_order={{ sort_order }}"
class="inline-flex rounded-xl border border-slate-300 px-4 py-2 text-sm font-medium text-slate-700 hover:bg-slate-50">
@@ -162,7 +162,25 @@
</div>
</section>
<section class="rounded-2xl bg-white p-6 shadow-soft">
<section class="rounded-2xl border border-slate-200 p-5 md:col-span-2">
<h3 class="text-sm font-semibold text-slate-900">Client Group / Family</h3>
<p class="mt-1 text-xs text-slate-500">Link this client to an existing family, promoter or related business group. Consultant access remains client-specific.</p>
<div class="mt-4 grid gap-4 md:grid-cols-3">
<label class="text-sm font-medium text-slate-700">Client Group
<select name="client_group_id" class="mt-1 w-full rounded-xl border border-slate-300 px-4 py-2 text-sm">
<option value="">-- No group --</option>
{% for g in form_options.client_groups or [] %}<option value="{{ g.id }}" {% if (form_data.client_group_id or (row.client_group_id if is_edit else None)) == g.id %}selected{% endif %}>{{ g.group_code }} — {{ g.group_name }}</option>{% endfor %}
</select>
</label>
<label class="text-sm font-medium text-slate-700">Relationship within group
<input name="group_relationship" value="{{ form_data.group_relationship or (row.group_relationship if is_edit else '') }}" placeholder="Spouse, HUF, Company, Trust..." class="mt-1 w-full rounded-xl border border-slate-300 px-4 py-2 text-sm">
</label>
<label class="mt-7 inline-flex items-center gap-2 text-sm font-medium text-slate-700"><input type="checkbox" name="is_group_head" {% if form_data.is_group_head or (is_edit and row.is_group_head) %}checked{% endif %}> Group head</label>
</div>
<div class="mt-3"><a href="/client-groups/new" class="text-sm font-medium text-brand-700 hover:underline">Create a new client group</a></div>
</section>
<section class="rounded-2xl bg-white p-6 shadow-soft">
<h3 class="text-base font-semibold text-slate-900">Assignment & Scope</h3>
<div class="mt-4 space-y-4">
<div>
@@ -1,2 +1,2 @@
<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">Code</th><th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Client</th><th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Association</th><th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Partner</th><th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Branch</th><th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Status</th><th class="px-4 py-3"></th></tr></thead><tbody class="divide-y divide-slate-100">{% for row in rows %}<tr><td class="px-4 py-3 text-sm font-medium text-slate-900">{{ row.client_code }}</td><td class="px-4 py-3 text-sm text-slate-700"><div class="font-medium">{{ row.client_name }}</div><div class="text-xs text-slate-500">{{ row.pan or row.gstin or '-' }}</div></td><td class="px-4 py-3 text-sm text-slate-700"><div>{{ row.association_type or 'legacy_firm' }}</div><div class="text-xs text-slate-500">{{ row.assoc_created_source or 'legacy' }}</div></td><td class="px-4 py-3 text-sm text-slate-700">{{ row.partner_name or row.effective_partner_id or '-' }}</td><td class="px-4 py-3 text-sm text-slate-700">{{ row.branch_name or row.assoc_firm_branch_id or row.branch_id or '-' }}</td><td class="px-4 py-3 text-sm">{% if row.status == 'active' %}<span class="rounded-full bg-emerald-100 px-2 py-1 text-xs font-medium text-emerald-700">Active</span>{% elif row.status == 'archived' %}<span class="rounded-full bg-amber-100 px-2 py-1 text-xs font-medium text-amber-800">Archived</span>{% else %}<span class="rounded-full bg-slate-200 px-2 py-1 text-xs font-medium text-slate-700">Inactive</span>{% endif %}</td><td class="px-4 py-3 text-right"><a href="/clients/{{ row.id }}" class="text-sm font-medium text-brand-700 hover:underline">Open</a></td></tr>{% else %}<tr><td colspan="7" class="px-4 py-8 text-center text-sm text-slate-500">No clients found.</td></tr>{% endfor %}</tbody></table></div>
<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">Code</th><th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Client</th><th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Group</th><th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Association</th><th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Partner</th><th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Branch</th><th class="px-4 py-3 text-left text-xs font-semibold uppercase tracking-wide text-slate-500">Status</th><th class="px-4 py-3"></th></tr></thead><tbody class="divide-y divide-slate-100">{% for row in rows %}<tr><td class="px-4 py-3 text-sm font-medium text-slate-900">{{ row.client_code }}</td><td class="px-4 py-3 text-sm text-slate-700"><div class="font-medium">{{ row.client_name }}</div><div class="text-xs text-slate-500">{{ row.pan or row.gstin or '-' }}</div></td><td class="px-4 py-3 text-sm text-slate-700">{% if row.client_group_name %}<a href="/client-groups/{{ row.client_group_id }}" class="font-medium text-brand-700">{{ row.client_group_name }}</a><div class="text-xs text-slate-500">{{ row.group_relationship or row.client_group_code }}</div>{% else %}-{% endif %}</td><td class="px-4 py-3 text-sm text-slate-700"><div>{{ row.association_type or 'legacy_firm' }}</div><div class="text-xs text-slate-500">{{ row.assoc_created_source or 'legacy' }}</div></td><td class="px-4 py-3 text-sm text-slate-700">{{ row.partner_name or row.effective_partner_id or '-' }}</td><td class="px-4 py-3 text-sm text-slate-700">{{ row.branch_name or row.assoc_firm_branch_id or row.branch_id or '-' }}</td><td class="px-4 py-3 text-sm">{% if row.status == 'active' %}<span class="rounded-full bg-emerald-100 px-2 py-1 text-xs font-medium text-emerald-700">Active</span>{% elif row.status == 'archived' %}<span class="rounded-full bg-amber-100 px-2 py-1 text-xs font-medium text-amber-800">Archived</span>{% else %}<span class="rounded-full bg-slate-200 px-2 py-1 text-xs font-medium text-slate-700">Inactive</span>{% endif %}</td><td class="px-4 py-3 text-right"><a href="/clients/{{ row.id }}" class="text-sm font-medium text-brand-700 hover:underline">Open</a></td></tr>{% else %}<tr><td colspan="8" class="px-4 py-8 text-center text-sm text-slate-500">No clients found.</td></tr>{% endfor %}</tbody></table></div>