Add Phase 3 client business intelligence profile

This commit is contained in:
A R R R Associates
2026-08-22 12:04:44 +05:30
parent f7bf1437ef
commit 397c887703
6 changed files with 467 additions and 0 deletions
@@ -0,0 +1,72 @@
{% extends "ui/templates/base/layout.html" %}
{% block content %}
<div class="space-y-6">
<div class="flex flex-col gap-3 md:flex-row md:items-center md:justify-between">
<div>
<a href="/clients/{{ row.id }}" class="text-sm font-medium text-brand-700 hover:underline">← Back to client</a>
<h2 class="mt-2 text-2xl font-semibold text-slate-900">Business Intelligence Profile</h2>
<p class="text-sm text-slate-500">{{ row.client_name }} · {{ row.client_code }}</p>
</div>
<div class="flex items-center gap-2">
<span class="rounded-full px-3 py-1 text-xs font-semibold {% if profile and profile.profile_status == 'confirmed' %}bg-emerald-100 text-emerald-700{% else %}bg-amber-100 text-amber-800{% endif %}">
{{ (profile.profile_status if profile else 'draft')|replace('_',' ')|title }}
</span>
<span class="rounded-full bg-slate-100 px-3 py-1 text-xs font-semibold text-slate-700">Confidence {{ profile.confidence_score if profile else 0 }}%</span>
</div>
</div>
<div class="rounded-2xl border border-sky-200 bg-sky-50 p-4 text-sm text-sky-900">
This server-side profile is an input to future accounting classification. GST, Income-tax, Tally and AI enrichment will add evidence here later; none of those sources can silently overwrite a user-confirmed profile.
</div>
<form method="post" action="/clients/{{ row.id }}/business-profile" class="rounded-2xl bg-white p-6 shadow-soft">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<div class="grid gap-5 md:grid-cols-2">
<label class="block"><span class="text-sm font-medium text-slate-700">Primary Industry</span><input name="primary_industry" value="{{ profile.primary_industry if profile else '' }}" {% if not can_edit %}disabled{% endif %} class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2"></label>
<label class="block"><span class="text-sm font-medium text-slate-700">Business Model</span><select name="business_model" {% if not can_edit %}disabled{% endif %} class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2"><option value="">Select</option>{% for option in business_model_options %}<option value="{{ option }}" {% if profile and profile.business_model == option %}selected{% endif %}>{{ option|replace('_',' ')|title }}</option>{% endfor %}</select></label>
<label class="block md:col-span-2"><span class="text-sm font-medium text-slate-700">Primary Business Activity</span><input name="primary_business_activity" value="{{ profile.primary_business_activity if profile else '' }}" {% if not can_edit %}disabled{% endif %} class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2"></label>
<label class="block md:col-span-2"><span class="text-sm font-medium text-slate-700">Secondary Business Activities</span><textarea name="secondary_business_activities" rows="3" {% if not can_edit %}disabled{% endif %} class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2">{{ profile.secondary_business_activities if profile else '' }}</textarea></label>
<label class="block"><span class="text-sm font-medium text-slate-700">Main Products</span><textarea name="main_products" rows="4" {% if not can_edit %}disabled{% endif %} class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2">{{ profile.main_products if profile else '' }}</textarea></label>
<label class="block"><span class="text-sm font-medium text-slate-700">Main Services</span><textarea name="main_services" rows="4" {% if not can_edit %}disabled{% endif %} class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2">{{ profile.main_services if profile else '' }}</textarea></label>
{% for field,label in [('inventory_maintained','Inventory Maintained'),('project_job_based','Project / Job Based'),('capital_intensive','Capital Intensive'),('vehicle_intensive','Vehicle Intensive')] %}
<label class="block"><span class="text-sm font-medium text-slate-700">{{ label }}</span><select name="{{ field }}" {% if not can_edit %}disabled{% endif %} class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2"><option value="unknown">Unknown</option><option value="yes" {% if profile and profile[field] is sameas true %}selected{% endif %}>Yes</option><option value="no" {% if profile and profile[field] is sameas false %}selected{% endif %}>No</option></select></label>
{% endfor %}
<label class="block md:col-span-2"><span class="text-sm font-medium text-slate-700">Profile Notes</span><textarea name="notes" rows="3" {% if not can_edit %}disabled{% endif %} class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2">{{ profile.notes if profile else '' }}</textarea></label>
</div>
{% if can_edit %}<div class="mt-5 flex gap-3"><button class="rounded-xl bg-brand-600 px-4 py-2 text-sm font-semibold text-white hover:bg-brand-700">Save Profile</button></div>{% endif %}
</form>
{% if can_edit %}
<div class="grid gap-6 xl:grid-cols-2">
<form method="post" action="/clients/{{ row.id }}/business-profile/sources" class="rounded-2xl bg-white p-6 shadow-soft">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<h3 class="font-semibold text-slate-900">Add Profile Evidence</h3>
<p class="mt-1 text-sm text-slate-500">Prepared for GST, Income-tax, Tally and future system enrichment.</p>
<div class="mt-4 grid gap-4 md:grid-cols-2">
<label><span class="text-sm text-slate-700">Source</span><select name="source_type" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2">{% for option in source_type_options %}<option value="{{ option }}">{{ option|replace('_',' ')|title }}</option>{% endfor %}</select></label>
<label><span class="text-sm text-slate-700">Confidence</span><input type="number" min="0" max="100" name="source_confidence" value="100" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2"></label>
<label><span class="text-sm text-slate-700">Reference</span><input name="source_reference" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2"></label>
<label><span class="text-sm text-slate-700">Observed On</span><input type="date" name="observed_on" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2"></label>
<label class="md:col-span-2 flex items-center gap-2"><input type="checkbox" name="is_authoritative" value="1"><span class="text-sm text-slate-700">Authoritative source</span></label>
<label class="md:col-span-2"><span class="text-sm text-slate-700">Notes</span><textarea name="source_notes" rows="2" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2"></textarea></label>
</div>
<button class="mt-4 rounded-xl border border-slate-300 px-4 py-2 text-sm font-semibold text-slate-700 hover:bg-slate-50">Add Evidence</button>
</form>
<div class="rounded-2xl bg-white p-6 shadow-soft">
<h3 class="font-semibold text-slate-900">Human Confirmation</h3>
<p class="mt-2 text-sm text-slate-600">Confirmation makes the current profile the authoritative accounting context. Editing it later automatically returns it to Draft for review.</p>
<form method="post" action="/clients/{{ row.id }}/business-profile/confirm" class="mt-5">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<button class="rounded-xl bg-emerald-600 px-4 py-2 text-sm font-semibold text-white hover:bg-emerald-700">Confirm Current Profile</button>
</form>
</div>
</div>
{% endif %}
<section class="rounded-2xl bg-white p-6 shadow-soft">
<h3 class="font-semibold text-slate-900">Evidence / Source History</h3>
<div class="mt-4 overflow-x-auto"><table class="min-w-full text-sm"><thead class="text-left text-xs uppercase text-slate-500"><tr><th class="px-3 py-2">Source</th><th class="px-3 py-2">Reference</th><th class="px-3 py-2">Observed</th><th class="px-3 py-2">Confidence</th><th class="px-3 py-2">Authority</th><th class="px-3 py-2">Notes</th></tr></thead><tbody class="divide-y divide-slate-100">{% for source in sources %}<tr><td class="px-3 py-3">{{ source.source_type|replace('_',' ')|title }}</td><td class="px-3 py-3">{{ source.source_reference or '-' }}</td><td class="px-3 py-3">{{ source.observed_on or '-' }}</td><td class="px-3 py-3">{{ source.confidence_score }}%</td><td class="px-3 py-3">{{ 'Authoritative' if source.is_authoritative else 'Supporting' }}</td><td class="px-3 py-3">{{ source.notes or '-' }}</td></tr>{% else %}<tr><td colspan="6" class="px-3 py-6 text-center text-slate-500">No profile evidence recorded yet.</td></tr>{% endfor %}</tbody></table></div>
</section>
</div>
{% endblock %}
@@ -9,6 +9,7 @@
<div class="flex flex-wrap gap-3">
{% if can_edit %}
<a href="/clients/{{ row.id }}/business-profile" class="rounded-xl border border-sky-300 px-4 py-2 text-sm font-medium text-sky-700 hover:bg-sky-50">Business Profile</a>
<a href="/clients/{{ row.id }}/business-structure" class="rounded-xl border border-emerald-300 px-4 py-2 text-sm font-medium text-emerald-700 hover:bg-emerald-50">Business Structure</a>
<a href="/registrations/clients/{{ row.id }}" class="rounded-xl border border-amber-300 px-4 py-2 text-sm font-medium text-amber-700 hover:bg-amber-50">Registrations</a>
<a href="/client-identity/clients/{{ row.id }}" class="rounded-xl border border-indigo-300 px-4 py-2 text-sm font-medium text-indigo-700 hover:bg-indigo-50">Portal Identity</a>