Prepare ERP source for Gitea deployment

This commit is contained in:
A R R R Associates
2026-06-20 15:01:44 +05:30
commit 5c75eb6bd9
450 changed files with 67698 additions and 0 deletions
@@ -0,0 +1,12 @@
{% set path = request.url.path %}
<div class="mb-6 overflow-x-auto rounded-2xl border border-slate-200 bg-white p-2 shadow-soft">
<div class="flex min-w-max gap-2 text-sm font-medium">
<a href="/partner/dashboard" class="rounded-xl px-4 py-2 transition {% if path == '/partner/dashboard' %}bg-brand-600 text-white{% else %}text-slate-700 hover:bg-slate-100{% endif %}">Overview</a>
<a href="/partner/reviews" class="rounded-xl px-4 py-2 transition {% if path.startswith('/partner/reviews') %}bg-brand-600 text-white{% else %}text-slate-700 hover:bg-slate-100{% endif %}">Review Board</a>
<a href="/partner/clients" class="rounded-xl px-4 py-2 transition {% if path.startswith('/partner/clients') %}bg-brand-600 text-white{% else %}text-slate-700 hover:bg-slate-100{% endif %}">My Clients</a>
<a href="/services/engagements" class="rounded-xl px-4 py-2 text-slate-700 transition hover:bg-slate-100">Engagements</a>
<a href="/documents" class="rounded-xl px-4 py-2 text-slate-700 transition hover:bg-slate-100">Documents</a>
<a href="/billing" class="rounded-xl px-4 py-2 text-slate-700 transition hover:bg-slate-100">Billing</a>
<a href="/alerts" class="rounded-xl px-4 py-2 transition {% if path.startswith('/alerts') %}bg-brand-600 text-white{% else %}text-slate-700 hover:bg-slate-100{% endif %}">My Alert</a>
</div>
</div>
@@ -0,0 +1,32 @@
{% extends "ui/templates/base/layout.html" %}
{% block content %}
{% include "modules/partners/templates/partners/_partner_tabs.html" %}
<div class="space-y-6">
<div class="rounded-3xl border border-slate-200 bg-white p-5 shadow-soft">
<div class="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
<div><h2 class="text-xl font-semibold">My Client Portfolio</h2><p class="text-sm text-slate-500">Client engagements assigned to you as engagement partner or review partner.</p></div>
<form method="get" class="flex gap-2"><input name="q" value="{{ q or '' }}" placeholder="Search" class="w-72 rounded-xl border border-slate-300 px-3 py-2 text-sm"><button class="rounded-xl bg-brand-600 px-4 py-2 text-sm font-semibold text-white">Search</button></form>
</div>
</div>
<div class="grid gap-4 lg:grid-cols-2 xl:grid-cols-3">
{% for engagement in payload.engagements %}
<a href="/partner/engagements/{{ engagement.id }}" class="rounded-3xl border border-slate-200 bg-white p-5 shadow-soft transition hover:border-brand-300 hover:bg-brand-50/30">
<div class="flex items-start justify-between gap-3">
<div><h3 class="font-semibold text-slate-900">{{ engagement.client_display }}</h3><p class="mt-1 text-sm text-slate-500">{{ engagement.display_label }}</p></div>
<span class="rounded-full bg-slate-100 px-2.5 py-1 text-xs font-semibold text-slate-700">{{ engagement.status|replace('_',' ')|title }}</span>
</div>
<div class="mt-4 grid grid-cols-3 gap-2 text-center text-xs">
<div class="rounded-2xl bg-slate-50 p-3"><div class="text-lg font-semibold">{{ engagement.task_counts.total }}</div><div class="text-slate-500">Tasks</div></div>
<div class="rounded-2xl bg-slate-50 p-3"><div class="text-lg font-semibold">{{ engagement.task_counts.open }}</div><div class="text-slate-500">Open</div></div>
<div class="rounded-2xl bg-slate-50 p-3"><div class="text-lg font-semibold">{{ engagement.task_counts.completed }}</div><div class="text-slate-500">Done</div></div>
</div>
<div class="mt-4 text-xs text-slate-500">{% if engagement.current_due_date %}Due: {{ engagement.current_due_date }}{% else %}No due date configured{% endif %}{% if engagement.is_overdue %}<span class="ml-2 rounded-full bg-red-100 px-2 py-1 font-semibold text-red-700">Overdue</span>{% endif %}</div>
</a>
{% else %}
<div class="rounded-3xl border border-dashed border-slate-300 bg-white p-8 text-center text-sm text-slate-500 xl:col-span-3">No assigned client engagements found.</div>
{% endfor %}
</div>
</div>
{% endblock %}
@@ -0,0 +1,88 @@
{% extends "ui/templates/base/layout.html" %}
{% block content %}
{% include "modules/partners/templates/partners/_partner_tabs.html" %}
<div class="space-y-6">
<section class="rounded-3xl bg-gradient-to-r from-brand-700 to-slate-900 p-6 text-white shadow-soft">
<div class="flex flex-col gap-4 lg:flex-row lg:items-center lg:justify-between">
<div>
<p class="text-sm uppercase tracking-[0.22em] text-brand-100">Partner Workspace</p>
<h2 class="mt-2 text-2xl font-semibold">Review, control and escalation dashboard</h2>
<p class="mt-2 max-w-3xl text-sm text-brand-100">Track assigned client engagements, pending reviews, blocked work, overdue items and documents requiring attention.</p>
{% if current_user_roles and ('Manager' in current_user_roles or 'Branch Manager' in current_user_roles or 'Firm Admin' in current_user_roles) %}
<p class="mt-3 inline-flex rounded-full bg-white/10 px-3 py-1 text-xs font-semibold text-white">Role-aware view: this partner login also carries team/administration responsibility.</p>
{% endif %}
</div>
<div class="flex flex-wrap gap-2">
<a href="/partner/reviews" class="rounded-xl bg-white px-4 py-2 text-sm font-semibold text-brand-700 hover:bg-brand-50">Open Review Board</a>
{% if current_user_roles and ('Manager' in current_user_roles or 'Branch Manager' in current_user_roles) %}<a href="/manager/dashboard" class="rounded-xl border border-white/40 px-4 py-2 text-sm font-semibold text-white hover:bg-white/10">Team Workspace</a>{% endif %}
</div>
</div>
</section>
<section class="grid gap-4 md:grid-cols-3 xl:grid-cols-6">
<a href="/partner/reviews" class="af-metric-card hover:border-brand-200"><div class="text-xs font-semibold uppercase text-slate-500">Tasks</div><div class="mt-2 text-3xl font-semibold">{{ payload.summary.total }}</div><div class="mt-1 text-xs text-slate-500">Visible portfolio</div></a>
<a href="/partner/reviews?status=pending_review" class="af-metric-card border-amber-200 bg-amber-50 hover:border-amber-300"><div class="text-xs font-semibold uppercase text-amber-700">Pending Review</div><div class="mt-2 text-3xl font-semibold text-amber-700">{{ payload.summary.pending_review }}</div><div class="mt-1 text-xs text-amber-700">Needs partner action</div></a>
<a href="/partner/reviews?status=blocked" class="af-metric-card border-red-200 bg-red-50 hover:border-red-300"><div class="text-xs font-semibold uppercase text-red-700">Blocked</div><div class="mt-2 text-3xl font-semibold text-red-700">{{ payload.summary.blocked }}</div><div class="mt-1 text-xs text-red-700">Escalation</div></a>
<a href="/partner/reviews?date_bucket=overdue" class="af-metric-card border-red-200 bg-red-50 hover:border-red-300"><div class="text-xs font-semibold uppercase text-red-700">Overdue</div><div class="mt-2 text-3xl font-semibold text-red-700">{{ payload.summary.overdue }}</div><div class="mt-1 text-xs text-red-700">High risk</div></a>
<a href="/partner/clients" class="af-metric-card hover:border-brand-200"><div class="text-xs font-semibold uppercase text-slate-500">Clients</div><div class="mt-2 text-3xl font-semibold">{{ payload.summary.clients }}</div><div class="mt-1 text-xs text-slate-500">Assigned clients</div></a>
<a href="/partner/reviews" class="af-metric-card hover:border-brand-200"><div class="text-xs font-semibold uppercase text-slate-500">Engagements</div><div class="mt-2 text-3xl font-semibold">{{ payload.summary.engagements }}</div><div class="mt-1 text-xs text-slate-500">Active portfolio</div></a>
</section>
<section class="grid gap-6 xl:grid-cols-[minmax(0,1.2fr)_420px]">
<div class="af-card">
<div class="flex items-center justify-between gap-3">
<div><h3 class="text-lg font-semibold text-slate-900">Attention Required</h3><p class="text-sm text-slate-500">Items that need partner review, decision or intervention.</p></div>
<a href="/partner/reviews" class="af-btn af-btn-primary">Open Review Board</a>
</div>
<div class="mt-5 space-y-3">
{% set shown = namespace(count=0) %}
{% for column in payload.columns %}
{% if column.code in ['pending_review', 'clarification_required', 'blocked'] %}
{% for task in column.tasks[:5] %}
{% set shown.count = shown.count + 1 %}
<a href="/partner/engagements/{{ task.subscription_id }}" class="block rounded-2xl border border-slate-200 p-4 transition hover:border-brand-300 hover:bg-brand-50/40">
<div class="flex items-start justify-between gap-3">
<div><div class="font-semibold text-slate-900">{{ task.task_name }}</div><div class="mt-1 text-sm text-slate-500">{{ task.client_display }} · {{ task.engagement_label }}</div></div>
<span class="af-badge {% if column.code == 'blocked' %}af-badge-danger{% elif column.code == 'pending_review' %}af-badge-warning{% else %}af-badge-info{% endif %}">{{ column.label }}</span>
</div>
<div class="mt-2 text-xs text-slate-500">Assigned to {{ task.assignee_display }}{% if task.internal_target_date %} · Target {{ task.internal_target_date }}{% endif %}</div>
</a>
{% endfor %}
{% endif %}
{% endfor %}
{% if shown.count == 0 %}<div class="rounded-2xl border border-dashed border-slate-300 p-8 text-center text-sm text-slate-500">No pending partner attention items found.</div>{% endif %}
</div>
</div>
<aside class="space-y-6">
<div class="af-card">
<div class="flex items-center justify-between gap-3"><div><h3 class="text-lg font-semibold text-slate-900">Client Portfolio</h3><p class="text-sm text-slate-500">Recent assigned engagements.</p></div><a href="/partner/clients" class="text-sm font-semibold text-brand-700 hover:underline">View all</a></div>
<div class="mt-4 space-y-3">
{% for engagement in payload.engagements[:6] %}
<a href="/partner/engagements/{{ engagement.id }}" class="block rounded-2xl border border-slate-200 p-4 hover:bg-slate-50">
<div class="font-semibold text-slate-900">{{ engagement.client_display }}</div>
<div class="mt-1 text-sm text-slate-500">{{ engagement.display_label }}</div>
<div class="mt-2 flex flex-wrap gap-2 text-xs"><span class="rounded-full bg-slate-100 px-2 py-1">Open {{ engagement.task_counts.open }}</span><span class="rounded-full bg-slate-100 px-2 py-1">Done {{ engagement.task_counts.completed }}</span>{% if engagement.is_overdue %}<span class="rounded-full bg-red-100 px-2 py-1 text-red-700">Overdue</span>{% endif %}</div>
</a>
{% else %}
<div class="rounded-2xl border border-dashed border-slate-300 p-6 text-center text-sm text-slate-500">No partner engagements found.</div>
{% endfor %}
</div>
</div>
{% if current_user_roles and ('Manager' in current_user_roles or 'Branch Manager' in current_user_roles or 'Firm Admin' in current_user_roles) %}
<div class="af-card border-brand-200 bg-brand-50/60">
<h3 class="font-semibold text-slate-900">Small Firm / Multi-role Actions</h3>
<p class="mt-1 text-sm text-slate-600">Use these when the partner is also handling manager-level follow-up.</p>
<div class="mt-4 grid gap-2 text-sm">
<a href="/manager/work" class="rounded-xl border border-brand-200 bg-white px-4 py-3 font-semibold text-brand-700 hover:bg-brand-50">Team Work Board</a>
<a href="/employees/progress" class="rounded-xl border border-brand-200 bg-white px-4 py-3 font-semibold text-brand-700 hover:bg-brand-50">Engagement Progress</a>
<a href="/employees/attendance" class="rounded-xl border border-brand-200 bg-white px-4 py-3 font-semibold text-brand-700 hover:bg-brand-50">Team Attendance</a>
</div>
</div>
{% endif %}
</aside>
</section>
</div>
{% endblock %}
@@ -0,0 +1,56 @@
{% extends "ui/templates/base/layout.html" %}
{% block content %}
{% include "modules/partners/templates/partners/_partner_tabs.html" %}
<div class="space-y-6">
<div class="rounded-3xl border border-slate-200 bg-white p-5 shadow-soft">
<div class="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
<div>
<p class="text-sm uppercase tracking-[0.18em] text-slate-400">Engagement Review</p>
<h2 class="mt-1 text-2xl font-semibold">{{ engagement.client.client_name if engagement.client else 'Client' }}</h2>
<p class="mt-1 text-sm text-slate-500">{{ engagement.display_label }}{% if engagement.current_due_date %} · Due {{ engagement.current_due_date }}{% endif %}</p>
</div>
<div class="flex flex-wrap gap-2"><a href="/documents?engagement_id={{ engagement.id }}" class="rounded-xl border border-slate-300 px-4 py-2 text-sm font-semibold text-slate-700 hover:bg-slate-50">Open Documents</a><a href="/services/engagements" class="rounded-xl border border-slate-300 px-4 py-2 text-sm font-semibold text-slate-700 hover:bg-slate-50">All Engagements</a></div>
</div>
</div>
<div class="grid gap-6 xl:grid-cols-[minmax(0,1fr)_360px]">
<section class="space-y-4">
{% for task in tasks %}
<div class="rounded-3xl border border-slate-200 bg-white p-5 shadow-soft">
<div class="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
<div><h3 class="font-semibold text-slate-900">{{ loop.index }}. {{ task.task_name }}</h3><p class="mt-1 text-sm text-slate-500">{{ task.description or 'No description.' }}</p><div class="mt-3 flex flex-wrap gap-2 text-xs"><span class="rounded-full bg-slate-100 px-2.5 py-1">{{ task.status_label }}</span><span class="rounded-full bg-slate-100 px-2.5 py-1">{{ task.priority_label }}</span><span class="rounded-full bg-slate-100 px-2.5 py-1">Assigned: {{ task.assignee_display }}</span>{% if task.is_overdue %}<span class="rounded-full bg-red-100 px-2.5 py-1 font-semibold text-red-700">Overdue</span>{% endif %}</div></div>
<a href="/employees/work/tasks/{{ task.id }}/communication" class="rounded-xl border border-slate-300 px-3 py-1.5 text-xs font-semibold text-slate-700 hover:bg-slate-50">Communication</a>
</div>
<form method="post" action="/partner/tasks/{{ task.id }}/review" class="mt-4 grid gap-3 rounded-2xl bg-slate-50 p-4 lg:grid-cols-[180px_minmax(0,1fr)_auto]">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<select name="action" class="rounded-xl border border-slate-300 px-3 py-2 text-sm"><option value="approve">Approve</option><option value="send_rework">Send for Rework</option><option value="clarification">Request Clarification</option></select>
<input name="message" placeholder="Optional partner note" class="rounded-xl border border-slate-300 px-3 py-2 text-sm">
<button class="rounded-xl bg-brand-600 px-4 py-2 text-sm font-semibold text-white hover:bg-brand-700">Submit</button>
</form>
{% if task.comments %}
<div class="mt-4 space-y-2">
{% for comment in task.comments[:3] %}
<div class="rounded-2xl border border-slate-200 p-3 text-sm"><div class="text-xs text-slate-500">{{ comment.comment_type|replace('_',' ')|title }} · {{ comment.created_at_utc }}</div><div class="mt-1 text-slate-700">{{ comment.message }}</div></div>
{% endfor %}
</div>
{% endif %}
</div>
{% else %}
<div class="rounded-3xl border border-dashed border-slate-300 bg-white p-8 text-center text-sm text-slate-500">No tasks found for this engagement.</div>
{% endfor %}
</section>
<aside class="rounded-3xl border border-slate-200 bg-white p-5 shadow-soft">
<div class="flex items-center justify-between gap-3"><div><h3 class="font-semibold">Documents</h3><p class="text-sm text-slate-500">Related engagement documents.</p></div><span class="rounded-full bg-slate-100 px-2.5 py-1 text-xs font-semibold">{{ documents|length }}</span></div>
<div class="mt-4 space-y-3">
{% for doc in documents %}
<div class="rounded-2xl border border-slate-200 p-4"><div class="font-medium text-slate-900">{{ doc.title }}</div><div class="mt-1 text-xs text-slate-500">{{ doc.document_type }} · v{{ doc.current_version_no }} · {{ doc.status|title }}</div></div>
{% else %}
<div class="rounded-2xl border border-dashed border-slate-300 p-6 text-center text-sm text-slate-500">No documents uploaded yet.</div>
{% endfor %}
</div>
</aside>
</div>
</div>
{% endblock %}
@@ -0,0 +1,31 @@
{% extends "ui/templates/base/layout.html" %}
{% block content %}
{% include "modules/partners/templates/partners/_partner_tabs.html" %}
<div class="space-y-6">
<div class="flex flex-col gap-3 rounded-3xl border border-slate-200 bg-white p-5 shadow-soft lg:flex-row lg:items-center lg:justify-between">
<div><h2 class="text-xl font-semibold">Partner Review Board</h2><p class="text-sm text-slate-500">Review completed work, blocked tasks, rework and in-progress engagement tasks.</p></div>
<form method="get" class="flex gap-2"><input name="q" value="{{ q or '' }}" placeholder="Search client, task or service" class="w-72 rounded-xl border border-slate-300 px-3 py-2 text-sm"><button class="rounded-xl bg-brand-600 px-4 py-2 text-sm font-semibold text-white">Search</button></form>
</div>
<div class="grid gap-4 xl:grid-cols-5">
{% for column in payload.columns %}
<section class="min-h-[420px] rounded-3xl border border-slate-200 bg-white p-4 shadow-soft">
<div class="mb-4 flex items-start justify-between gap-3"><div><h3 class="font-semibold">{{ column.label }}</h3><p class="text-xs text-slate-500">{{ column.hint }}</p></div><span class="rounded-full bg-slate-100 px-2.5 py-1 text-xs font-semibold">{{ column.count }}</span></div>
<div class="space-y-3">
{% for task in column.tasks %}
<div class="rounded-2xl border border-slate-200 p-4">
<div class="flex items-start justify-between gap-3"><div><a href="/work/engagements/{{ task.subscription_id }}" class="font-semibold text-slate-900 hover:text-brand-700">{{ task.task_name }}</a><div class="mt-1 text-xs text-slate-500">{{ task.client_display }}</div></div>{% if task.is_overdue %}<span class="rounded-full bg-red-100 px-2 py-1 text-[11px] font-semibold text-red-700">Overdue</span>{% endif %}</div>
<div class="mt-2 text-xs text-slate-500">{{ task.engagement_label }}</div>
<div class="mt-3 flex flex-wrap gap-2 text-[11px]"><span class="rounded-full bg-slate-100 px-2 py-1">{{ task.status_label }}</span><span class="rounded-full bg-slate-100 px-2 py-1">{{ task.priority_label }}</span><span class="rounded-full bg-slate-100 px-2 py-1">{{ task.assignee_display }}</span></div>
<a href="/work/engagements/{{ task.subscription_id }}" class="mt-3 inline-flex rounded-xl border border-slate-300 px-3 py-1.5 text-xs font-semibold text-slate-700 hover:bg-slate-50">Open Review Details</a>
</div>
{% else %}
<div class="rounded-2xl border border-dashed border-slate-300 p-6 text-center text-xs text-slate-500">No items.</div>
{% endfor %}
</div>
</section>
{% endfor %}
</div>
</div>
{% endblock %}