Unify accounting analysis on local SQLite mirror

This commit is contained in:
A R R R Associates
2026-09-06 20:13:51 +05:30
parent 6c2a2081ed
commit 7adbbde220
11 changed files with 848 additions and 129 deletions
@@ -91,10 +91,9 @@
{% if review %}
<section class="space-y-4">
<div class="rounded-2xl border border-emerald-200 bg-emerald-50 px-4 py-3 text-sm text-emerald-800">
Analysis completed entirely from the local SQLite Accounting Mirror. TallyPrime was not contacted.
{% if review.cash_ledgers %} Cash ledger(s): <strong>{{ review.cash_ledgers|join(', ') }}</strong>.{% endif %}
{% if review.mirror_period %} Mirror period: {{ review.mirror_period.from_date or '—' }} → {{ review.mirror_period.to_date or '—' }}.{% endif %}
<div class="flex flex-wrap justify-end gap-2">
<a href="/tools/tally/analysis/{{ review.analysis_run_id }}/download?client_id={{ selected_client.id }}&financial_year={{ date_from[:4] }}-{{ date_to[2:4] }}&format=xlsx" class="rounded-xl border border-emerald-300 bg-emerald-50 px-4 py-2 text-sm font-semibold text-emerald-800">Download Excel</a>
<a href="/tools/tally/analysis/{{ review.analysis_run_id }}/download?client_id={{ selected_client.id }}&financial_year={{ date_from[:4] }}-{{ date_to[2:4] }}&format=pdf" class="rounded-xl border border-slate-300 bg-white px-4 py-2 text-sm font-semibold text-slate-700">Download PDF</a>
</div>
<div class="grid gap-4 md:grid-cols-2 xl:grid-cols-5">
{% for label, value in [('Vouchers reviewed', review.summary.vouchers_reviewed), ('Cash payments', review.summary.cash_payment_vouchers), ('Single-voucher exceptions', review.summary.single_voucher_exceptions), ('Same-day exceptions', review.summary.same_day_exceptions), ('Possible split patterns', review.summary.possible_split_patterns)] %}
@@ -1,14 +1,12 @@
{% extends "ui/templates/base/layout.html" %}
{% block content %}
{% set agent = live_result.agent if live_result else None %}
{% set tally = live_result.tally if live_result else None %}
{% set accounting = live_result.accounting if live_result else None %}
{% set mirror = mirror_status.mirror if mirror_status and mirror_status.mirror else {} %}
<div class="space-y-6">
<div class="flex flex-wrap items-start justify-between gap-4">
<div>
<p class="text-xs font-semibold uppercase tracking-[0.16em] text-brand-600">Tools · Tally · Phase 6</p>
<p class="text-xs font-semibold uppercase tracking-[0.16em] text-brand-600">Tools · Accounting</p>
<h1 class="mt-1 text-2xl font-semibold text-slate-900">Depreciation (Income Tax)</h1>
<p class="mt-1 text-sm text-slate-500">Calculate Income-tax depreciation, approve the reviewed draft and—only after explicit confirmation—post the approved Journal to the mapped company currently open in TallyPrime.</p>
<p class="mt-1 text-sm text-slate-500">Calculate Income-tax depreciation from the client SQLite Accounting Mirror. Approved drafts retain the existing controlled Tally write-back.</p>
</div>
<a href="/tools/tally{% if selected_client %}?client_id={{ selected_client.id }}&refresh=1{% endif %}" class="rounded-xl border border-slate-300 bg-white px-4 py-2 text-sm font-semibold text-slate-700 hover:bg-slate-50">Back to Tally</a>
</div>
@@ -19,15 +17,14 @@
{% if command_error %}<div class="rounded-xl border border-red-200 bg-red-50 px-4 py-3 text-sm text-red-800">{{ command_error }}</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 font-semibold uppercase tracking-wide text-slate-500">ERP Local Agent</div><div class="mt-2 text-lg font-semibold {{ 'text-emerald-700' if agent_online else 'text-red-700' }}">{{ 'Connected' if agent_online else 'Offline' }}</div><div class="mt-1 text-xs text-slate-500">Agent {{ agent.version if agent and agent.version else '-' }}</div></div>
<div class="rounded-2xl bg-white p-5 shadow-soft"><div class="text-xs font-semibold uppercase tracking-wide text-slate-500">TallyPrime</div><div class="mt-2 text-lg font-semibold {{ 'text-emerald-700' if tally and tally.connected else 'text-slate-700' }}">{{ 'Connected' if tally and tally.connected else 'Not connected' }}</div><div class="mt-1 text-xs text-slate-500">{{ tally.company_count if tally else 0 }} currently loaded</div></div>
<div class="rounded-2xl bg-white p-5 shadow-soft"><div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Phase 6</div><div class="mt-2 text-lg font-semibold {{ 'text-emerald-700' if agent and agent.tally_writeback_capability else 'text-slate-700' }}">{{ 'Available' if agent and agent.tally_writeback_capability else 'Update Agent' }}</div><div class="mt-1 text-xs text-slate-500">Controlled approved write-back</div></div>
<div class="rounded-2xl bg-white p-5 shadow-soft"><div class="text-xs font-semibold uppercase tracking-wide text-slate-500">ERP Local Agent</div><div class="mt-2 text-lg font-semibold {{ 'text-emerald-700' if agent_online else 'text-red-700' }}">{{ 'Connected' if agent_online else 'Offline' }}</div></div>
<div class="rounded-2xl bg-white p-5 shadow-soft"><div class="text-xs font-semibold uppercase tracking-wide text-slate-500">SQLite Mirror</div><div class="mt-2 text-lg font-semibold {{ 'text-emerald-700' if mirror.ready else 'text-amber-700' }}">{{ 'Ready' if mirror.ready else 'Mirror required' }}</div><div class="mt-1 text-xs text-slate-500">{{ mirror.company.company_name if mirror.ready and mirror.company else '' }}</div></div>
<div class="rounded-2xl bg-white p-5 shadow-soft"><div class="text-xs font-semibold uppercase tracking-wide text-slate-500">Write-back</div><div class="mt-2 text-lg font-semibold text-slate-700">Controlled</div><div class="mt-1 text-xs text-slate-500">Tally is contacted only after approval/posting.</div></div>
</section>
<section class="rounded-2xl bg-white p-5 shadow-soft">
<form method="get" action="/tools/tally/depreciation" class="grid gap-4 lg:grid-cols-4 lg:items-end">
<form method="get" action="/tools/tally/depreciation" class="grid gap-4 lg:grid-cols-3 lg:items-end">
<div><label class="text-sm font-medium text-slate-700">ERP Client</label><select name="client_id" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2" onchange="this.form.submit()"><option value="">Select client</option>{% for client in clients %}<option value="{{ client.id }}" {% if selected_client and selected_client.id == client.id %}selected{% endif %}>{{ client.client_name }}</option>{% endfor %}</select></div>
<div><label class="text-sm font-medium text-slate-700">Currently Open in TallyPrime</label><select name="tally_guid" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2" {% if not selected_client %}disabled{% endif %}><option value="">Select mapped open company</option>{% if tally %}{% for company in tally.companies or [] %}<option value="{{ company.guid }}" {% if selected_tally_guid == company.guid %}selected{% endif %}>{{ company.name }}{% if company.gstin %} · {{ company.gstin }}{% endif %}</option>{% endfor %}{% endif %}</select></div>
<div><label class="text-sm font-medium text-slate-700">Financial Year</label><div class="mt-1 grid grid-cols-2 gap-2"><input type="date" name="fy_start" value="{{ fy_start }}" class="w-full rounded-xl border border-slate-300 px-3 py-2"><input type="date" name="fy_end" value="{{ fy_end }}" class="w-full rounded-xl border border-slate-300 px-3 py-2"></div></div>
<button type="submit" class="rounded-xl bg-brand-600 px-4 py-2 text-sm font-semibold text-white hover:bg-brand-700">Load Fixed Assets</button>
</form>
@@ -37,14 +34,14 @@
{% set coverage = preview.transaction_coverage %}
<div class="rounded-xl border {{ 'border-emerald-200 bg-emerald-50 text-emerald-800' if coverage.complete else 'border-amber-200 bg-amber-50 text-amber-900' }} px-4 py-3 text-sm">
{% if coverage.complete %}
Phase 4 transaction data covers the required period {{ coverage.required_from }} to {{ coverage.required_to }}{% if coverage.provisional %}. This is a provisional current-FY calculation; future dates are not required yet{% endif %}.
SQLite mirror data covers the required period {{ coverage.required_from }} to {{ coverage.required_to }}{% if coverage.provisional %}. This is a provisional current-FY calculation; future dates are not required yet{% endif %}.
{% else %}
Phase 4 transaction data does not yet cover {{ coverage.required_from }} to {{ coverage.required_to }}. You may save a draft, but approval/write-back will remain blocked until the missing period is synchronized.
SQLite mirror data does not yet cover {{ coverage.required_from }} to {{ coverage.required_to }}. You may save a draft, but approval/write-back will remain blocked until the required FY is mirrored.
{% endif %}
</div>
<form method="post" action="/tools/tally/depreciation/calculate" class="space-y-5">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}"><input type="hidden" name="client_id" value="{{ selected_client.id }}"><input type="hidden" name="tally_guid" value="{{ selected_tally_guid }}"><input type="hidden" name="fy_start" value="{{ fy_start }}"><input type="hidden" name="fy_end" value="{{ fy_end }}">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}"><input type="hidden" name="client_id" value="{{ selected_client.id }}"><input type="hidden" name="fy_start" value="{{ fy_start }}"><input type="hidden" name="fy_end" value="{{ fy_end }}">
<section class="rounded-2xl bg-white p-5 shadow-soft">
<div class="grid gap-4 md:grid-cols-2">
<div><label class="text-sm font-medium text-slate-700">Depreciation Expense Ledger</label><select name="depreciation_expense_ledger" class="mt-1 w-full rounded-xl border border-slate-300 px-3 py-2"><option value="">Depreciation</option>{% for name in preview.all_ledgers %}<option value="{{ name }}">{{ name }}</option>{% endfor %}</select></div>
@@ -82,6 +79,12 @@
{% endif %}
{% if depreciation_run %}
{% if depreciation_run.analysis_run_id %}
<div class="flex justify-end gap-2">
<a href="/tools/tally/analysis/{{ depreciation_run.analysis_run_id }}/download?client_id={{ selected_client.id }}&financial_year={{ fy_start[:4] }}-{{ fy_end[2:4] }}&format=xlsx" class="rounded-xl border border-emerald-300 bg-emerald-50 px-4 py-2 text-sm font-semibold text-emerald-800">Download Excel</a>
<a href="/tools/tally/analysis/{{ depreciation_run.analysis_run_id }}/download?client_id={{ selected_client.id }}&financial_year={{ fy_start[:4] }}-{{ fy_end[2:4] }}&format=pdf" class="rounded-xl border border-slate-300 bg-white px-4 py-2 text-sm font-semibold">Download PDF</a>
</div>
{% endif %}
<section class="rounded-2xl bg-white p-5 shadow-soft"><div class="flex flex-wrap justify-between gap-4"><div><h2 class="font-semibold text-slate-900">Draft Calculation #{{ depreciation_run.id }}</h2><p class="mt-1 text-sm text-slate-500">{{ depreciation_run.company_name }} · {{ depreciation_run.fy_start }} to {{ depreciation_run.fy_end }}</p></div><div class="text-right"><div class="text-xs uppercase tracking-wide text-slate-500">Total Depreciation</div><div class="text-2xl font-semibold text-slate-900">₹ {{ '%.2f'|format(depreciation_run.total_depreciation) }}</div></div></div>
<div class="mt-4 rounded-xl border border-blue-200 bg-blue-50 px-4 py-3 text-sm text-blue-800">Journal: Debit <strong>{{ depreciation_run.depreciation_expense_ledger or 'Depreciation' }}</strong> and credit <strong>{{ depreciation_run.depreciation_reserve_ledger or 'Depreciation Reserve' }}</strong> for ₹ {{ '%.2f'|format(depreciation_run.total_depreciation) }}. Voucher date will be {{ depreciation_run.fy_end }} and reference ARRR-ITDEP-{{ depreciation_run.id }}.</div>
<div class="mt-4 grid gap-3 md:grid-cols-3">
@@ -148,4 +151,10 @@
})();
</script>
{% if analysis_history %}
<section class="rounded-2xl bg-white p-5 shadow-soft">
<h2 class="font-semibold text-slate-900">Depreciation Analysis History</h2>
<div class="mt-3 overflow-x-auto"><table class="min-w-full text-sm"><thead><tr class="text-left text-xs uppercase text-slate-500"><th class="p-2">Run</th><th class="p-2">FY</th><th class="p-2">Period</th><th class="p-2">Completed</th><th class="p-2"></th></tr></thead><tbody>{% for row in analysis_history %}<tr class="border-t"><td class="p-2">#{{ row.id }}</td><td class="p-2">{{ row.financial_year }}</td><td class="p-2">{{ row.period_from }} → {{ row.period_to }}</td><td class="p-2">{{ row.completed_at_utc }}</td><td class="p-2 text-right"><a class="font-semibold text-brand-700" href="/tools/tally/analysis/{{ row.id }}/download?client_id={{ selected_client.id }}&financial_year={{ row.financial_year }}&format=xlsx">Excel</a> · <a class="font-semibold text-brand-700" href="/tools/tally/analysis/{{ row.id }}/download?client_id={{ selected_client.id }}&financial_year={{ row.financial_year }}&format=pdf">PDF</a></td></tr>{% endfor %}</tbody></table></div>
</section>
{% endif %}
{% endblock %}
@@ -22,33 +22,29 @@
<section class="rounded-2xl bg-white p-5 shadow-soft">
<form method="get" class="grid gap-4 md:grid-cols-[1.5fr_auto]">
<label class="text-sm font-semibold">ERP Client
<select name="client_id" required class="mt-1 w-full rounded-xl border border-slate-300 bg-white px-3 py-2">
<select name="client_id" required class="mt-1 w-full rounded-xl border border-slate-300 bg-white px-3 py-2" onchange="this.form.submit()">
<option value="">Select client</option>
{% for client in clients %}
<option value="{{ client.id }}" {% if selected_client and selected_client.id==client.id %}selected{% endif %}>{{ client.client_code }} · {{ client.client_name }}</option>
{% endfor %}
</select>
</label>
<div class="flex items-end"><button class="rounded-xl bg-brand-600 px-5 py-2 text-sm font-semibold text-white">Load Tally Companies</button></div>
<div class="flex items-end"><a href="/tools/tally{% if selected_client %}?client_id={{ selected_client.id }}{% endif %}" class="rounded-xl border border-slate-300 bg-white px-5 py-2 text-sm font-semibold">Manage Mirrors</a></div>
</form>
{% if selected_client %}
<form method="post" action="/tools/accounting/opening-balances/compare" class="mt-5 grid gap-4 rounded-xl border border-slate-200 bg-slate-50 p-4 md:grid-cols-[1fr_1fr_auto]">
{% set prev = previous_mirror_status.mirror if previous_mirror_status and previous_mirror_status.mirror else {} %}
{% set curr = current_mirror_status.mirror if current_mirror_status and current_mirror_status.mirror else {} %}
<div class="mt-5 grid gap-3 md:grid-cols-2">
<div class="rounded-xl border p-4 {{ 'border-emerald-200 bg-emerald-50' if prev.ready else 'border-amber-200 bg-amber-50' }}"><div class="text-xs font-semibold uppercase text-slate-500">Previous FY Mirror · {{ previous_fy }}</div><div class="mt-1 font-semibold">{{ 'Ready' if prev.ready else 'Mirror required' }}</div>{% if prev.ready %}<div class="mt-1 text-xs text-slate-500">{{ prev.company.company_name }} · {{ prev.counts.voucher }} vouchers</div>{% endif %}</div>
<div class="rounded-xl border p-4 {{ 'border-emerald-200 bg-emerald-50' if curr.ready else 'border-amber-200 bg-amber-50' }}"><div class="text-xs font-semibold uppercase text-slate-500">Current FY Mirror · {{ current_fy }}</div><div class="mt-1 font-semibold">{{ 'Ready' if curr.ready else 'Mirror required' }}</div>{% if curr.ready %}<div class="mt-1 text-xs text-slate-500">{{ curr.company.company_name }} · {{ curr.counts.voucher }} vouchers</div>{% endif %}</div>
</div>
<form method="post" action="/tools/accounting/opening-balances/compare" class="mt-4 flex flex-wrap items-end gap-3">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="hidden" name="client_id" value="{{ selected_client.id }}">
<label class="text-xs font-semibold">Previous-Year Tally Company
<select name="previous_company_name" required class="mt-1 w-full rounded-lg border border-slate-300 bg-white px-3 py-2">
<option value="">Select previous-year company</option>
{% for company in companies %}<option value="{{ company.name }}">{{ company.name }}</option>{% endfor %}
</select>
</label>
<label class="text-xs font-semibold">Current-Year Tally Company
<select name="current_company_name" required class="mt-1 w-full rounded-lg border border-slate-300 bg-white px-3 py-2">
<option value="">Select current-year company</option>
{% for company in companies %}<option value="{{ company.name }}">{{ company.name }}</option>{% endfor %}
</select>
</label>
<div class="flex items-end"><button class="rounded-xl bg-slate-900 px-5 py-2 text-sm font-semibold text-white" {% if not node_online %}disabled{% endif %}>Compare Opening Balances</button></div>
<input type="hidden" name="previous_fy" value="{{ previous_fy }}">
<input type="hidden" name="current_fy" value="{{ current_fy }}">
<button class="rounded-xl bg-slate-900 px-5 py-2 text-sm font-semibold text-white" {% if not node_online or not prev.ready or not curr.ready %}disabled{% endif %}>Compare Opening Balances</button>
</form>
{% endif %}
</section>
@@ -77,8 +73,9 @@
{% endif %}
{% if selected_run %}
<div class="mb-4 flex justify-end">
<div class="mb-4 flex justify-end gap-2">
<a href="/tools/accounting/opening-balances/download/{{ selected_run.id }}?client_id={{ selected_client.id }}" class="rounded-xl border border-emerald-300 bg-emerald-50 px-4 py-2 text-sm font-semibold text-emerald-800">Download Excel Report</a>
{% if analysis_run_id %}<a href="/tools/tally/analysis/{{ analysis_run_id }}/download?client_id={{ selected_client.id }}&financial_year={{ current_fy }}&format=pdf" class="rounded-xl border border-slate-300 bg-white px-4 py-2 text-sm font-semibold">Download PDF</a>{% endif %}
</div>
<section class="rounded-2xl bg-white p-5 shadow-soft">
@@ -48,6 +48,10 @@
<a href="/tools/tally/depreciation{% if selected_client %}?client_id={{ selected_client.id }}{% endif %}" class="rounded-xl border border-slate-300 bg-white px-3 py-2 text-sm font-semibold">Depreciation (IT)</a>
<a href="/tools/accounting/cash-payments{% if selected_client %}?client_id={{ selected_client.id }}{% endif %}" class="rounded-xl border border-orange-300 bg-white px-3 py-2 text-sm font-semibold text-orange-800">Cash Payment Compliance</a>
<a href="/tools/accounting/cash-payments/allocation{% if selected_client %}?client_id={{ selected_client.id }}{% endif %}" class="rounded-xl border border-amber-300 bg-white px-3 py-2 text-sm font-semibold text-amber-800">Cash Payment Entry Allocation</a>
<a href="/tools/accounting/tds{% if selected_client %}?client_id={{ selected_client.id }}{% endif %}" class="rounded-xl border border-violet-300 bg-white px-3 py-2 text-sm font-semibold text-violet-800">TDS Compliance Review</a>
<a href="/tools/accounting/tds/rules" class="rounded-xl border border-violet-200 bg-white px-3 py-2 text-sm font-semibold text-violet-700">TDS Rules</a>
<a href="/tools/accounting/tds/liability{% if selected_client %}?client_id={{ selected_client.id }}{% endif %}" class="rounded-xl border border-violet-200 bg-white px-3 py-2 text-sm font-semibold text-violet-700">TDS Liability</a>
<a href="/tools/accounting/tds/reconciliation{% if selected_client %}?client_id={{ selected_client.id }}{% endif %}" class="rounded-xl border border-violet-200 bg-white px-3 py-2 text-sm font-semibold text-violet-700">TDS Reconciliation</a>
<a href="/tools/accounting/ai{% if selected_client %}?client_id={{ selected_client.id }}{% endif %}" class="rounded-xl border border-indigo-300 bg-indigo-50 px-3 py-2 text-sm font-semibold text-indigo-800">Accounting AI</a>
<a href="/tools/accounting/internal-model" class="rounded-xl border border-emerald-300 bg-emerald-50 px-3 py-2 text-sm font-semibold text-emerald-800">Internal Model</a>
</div>
@@ -169,7 +173,13 @@
{% set active_mappings = (accounting.mappings or []) | selectattr('is_active') | list %}
{% if active_mappings %}
{% set current_mapping = active_mappings[0] %}
<details class="rounded-2xl border border-slate-200 bg-white shadow-soft">
{% if selected_client and analysis_history %}
<section class="rounded-2xl bg-white p-5 shadow-soft">
<div class="flex items-center justify-between gap-3"><div><h2 class="font-semibold text-slate-900">Recent Accounting Analysis</h2><p class="mt-1 text-sm text-slate-500">Stored in the client local SQLite accounting database.</p></div></div>
<div class="mt-3 overflow-x-auto"><table class="min-w-full text-sm"><thead><tr class="text-left text-xs uppercase text-slate-500"><th class="p-2">Run</th><th class="p-2">Analysis</th><th class="p-2">FY / Period</th><th class="p-2">Completed</th><th class="p-2"></th></tr></thead><tbody>{% for row in analysis_history %}<tr class="border-t"><td class="p-2">#{{ row.id }}</td><td class="p-2 font-medium">{{ row.analysis_type|replace('_',' ')|title }}</td><td class="p-2">{{ row.financial_year }} · {{ row.period_from }} → {{ row.period_to }}</td><td class="p-2">{{ row.completed_at_utc }}</td><td class="p-2 text-right"><a class="font-semibold text-brand-700" href="/tools/tally/analysis/{{ row.id }}/download?client_id={{ selected_client.id }}&financial_year={{ row.financial_year }}&format=xlsx">Excel</a> · <a class="font-semibold text-brand-700" href="/tools/tally/analysis/{{ row.id }}/download?client_id={{ selected_client.id }}&financial_year={{ row.financial_year }}&format=pdf">PDF</a></td></tr>{% endfor %}</tbody></table></div>
</section>
{% endif %}
<details class="rounded-2xl border border-slate-200 bg-white shadow-soft">
<summary class="cursor-pointer list-none px-5 py-4">
<div class="flex flex-wrap items-center justify-between gap-3">
<div>
@@ -1,5 +1,5 @@
{% extends "ui/templates/base/layout.html" %}
{% block content %}
<div class="space-y-6">
<div class="flex flex-wrap items-start justify-between gap-3"><div><p class="text-xs font-semibold uppercase tracking-[0.16em] text-violet-600">TDS &amp; Withholding Tax</p><h1 class="mt-1 text-2xl font-semibold text-slate-900">TDS Compliance Review</h1><p class="mt-1 text-sm text-slate-500">Read-only Tally scan across expenses, purchases, capital/service purchases, journals and creditor postings. Rules and thresholds come from the editable TDS Rule Master.</p></div><div class="flex gap-2"><a href="/tools/accounting/tds/rules" class="rounded-xl border px-3 py-2 text-sm font-semibold">Rule Master</a><a href="/tools/tally" class="rounded-xl border px-3 py-2 text-sm font-semibold">Tally</a></div></div>{% if error %}<div class="rounded-xl bg-red-50 p-3 text-sm text-red-800">{{ error }}</div>{% endif %}<form method="get" class="rounded-2xl bg-white p-5 shadow-soft"><div class="grid gap-3 lg:grid-cols-4"><label class="text-sm">Client<select name="client_id" required class="mt-1 w-full rounded-xl border px-3 py-2"><option value="">Select client</option>{% for c in clients %}<option value="{{ c.id }}" {% if selected_client and c.id==selected_client.id %}selected{% endif %}>{{ c.client_name }}</option>{% endfor %}</select></label><label class="text-sm">Tally company GUID<input name="tally_guid" value="{{ tally_guid or '' }}" required class="mt-1 w-full rounded-xl border px-3 py-2" placeholder="Select/copy GUID from mapped/open company"></label><label class="text-sm">From<input type="date" name="date_from" value="{{ date_from }}" required class="mt-1 w-full rounded-xl border px-3 py-2"></label><label class="text-sm">To<input type="date" name="date_to" value="{{ date_to }}" required class="mt-1 w-full rounded-xl border px-3 py-2"></label></div><input type="hidden" name="run" value="1"><button class="mt-4 rounded-xl bg-violet-700 px-4 py-2 text-sm font-semibold text-white">Run TDS Review</button></form>{% if review %}<div class="grid gap-3 sm:grid-cols-2 lg:grid-cols-5">{% for k,v in review.summary.items() %}<div class="rounded-xl bg-white p-4 shadow-soft"><div class="text-xs uppercase text-slate-500">{{ k|replace('_',' ') }}</div><div class="mt-1 text-xl font-semibold">{{ v }}</div></div>{% endfor %}</div><div class="overflow-x-auto rounded-2xl bg-white shadow-soft"><table class="min-w-full text-sm"><thead class="bg-slate-50"><tr><th class="p-3 text-left">Date</th><th class="p-3 text-left">Party</th><th class="p-3 text-left">Ledger / Rule</th><th class="p-3 text-right">Base</th><th class="p-3 text-right">Expected</th><th class="p-3 text-right">Actual</th><th class="p-3 text-right">Liability</th><th class="p-3 text-left">Status</th></tr></thead><tbody>{% for x in review.transactions %}<tr class="border-t"><td class="p-3">{{ x.date }}</td><td class="p-3">{{ x.party }}</td><td class="p-3">{{ x.nature_ledger }}<div class="text-xs text-slate-500">{{ x.rule_name }} · {{ x.legacy_section }}</div></td><td class="p-3 text-right">{{ '%.2f'|format(x.taxable_base) }}</td><td class="p-3 text-right">{{ '%.2f'|format(x.expected_tds) }}</td><td class="p-3 text-right">{{ '%.2f'|format(x.actual_tds) }}</td><td class="p-3 text-right font-semibold">{{ '%.2f'|format(x.liability) }}</td><td class="p-3">{{ x.status }}</td></tr>{% endfor %}</tbody></table></div>{% endif %}</div>
<div class="flex flex-wrap items-start justify-between gap-3"><div><p class="text-xs font-semibold uppercase tracking-[0.16em] text-violet-600">TDS &amp; Withholding Tax</p><h1 class="mt-1 text-2xl font-semibold text-slate-900">TDS Compliance Review</h1><p class="mt-1 text-sm text-slate-500">Review expenses, purchases, journals and creditor postings from the client SQLite Accounting Mirror. Rules and thresholds come from the editable TDS Rule Master.</p></div><div class="flex gap-2"><a href="/tools/accounting/tds/rules" class="rounded-xl border px-3 py-2 text-sm font-semibold">Rule Master</a><a href="/tools/tally" class="rounded-xl border px-3 py-2 text-sm font-semibold">Tally</a></div></div>{% if error %}<div class="rounded-xl bg-red-50 p-3 text-sm text-red-800">{{ error }}</div>{% endif %}<form method="get" class="rounded-2xl bg-white p-5 shadow-soft"><div class="grid gap-3 lg:grid-cols-3"><label class="text-sm">Client<select name="client_id" required class="mt-1 w-full rounded-xl border px-3 py-2"><option value="">Select client</option>{% for c in clients %}<option value="{{ c.id }}" {% if selected_client and c.id==selected_client.id %}selected{% endif %}>{{ c.client_name }}</option>{% endfor %}</select></label><label class="text-sm">From<input type="date" name="date_from" value="{{ date_from }}" required class="mt-1 w-full rounded-xl border px-3 py-2"></label><label class="text-sm">To<input type="date" name="date_to" value="{{ date_to }}" required class="mt-1 w-full rounded-xl border px-3 py-2"></label></div><input type="hidden" name="run" value="1"><button class="mt-4 rounded-xl bg-violet-700 px-4 py-2 text-sm font-semibold text-white">Run TDS Review</button></form>{% if review %}<div class="flex justify-end gap-2"><a href="/tools/tally/analysis/{{ review.analysis_run_id }}/download?client_id={{ selected_client.id }}&financial_year={{ date_from[:4] }}-{{ date_to[2:4] }}&format=xlsx" class="rounded-xl border border-emerald-300 bg-emerald-50 px-3 py-2 text-sm font-semibold text-emerald-800">Download Excel</a><a href="/tools/tally/analysis/{{ review.analysis_run_id }}/download?client_id={{ selected_client.id }}&financial_year={{ date_from[:4] }}-{{ date_to[2:4] }}&format=pdf" class="rounded-xl border px-3 py-2 text-sm font-semibold">Download PDF</a></div><div class="grid gap-3 sm:grid-cols-2 lg:grid-cols-5">{% for k,v in review.summary.items() %}<div class="rounded-xl bg-white p-4 shadow-soft"><div class="text-xs uppercase text-slate-500">{{ k|replace('_',' ') }}</div><div class="mt-1 text-xl font-semibold">{{ v }}</div></div>{% endfor %}</div><div class="overflow-x-auto rounded-2xl bg-white shadow-soft"><table class="min-w-full text-sm"><thead class="bg-slate-50"><tr><th class="p-3 text-left">Date</th><th class="p-3 text-left">Party</th><th class="p-3 text-left">Ledger / Rule</th><th class="p-3 text-right">Base</th><th class="p-3 text-right">Expected</th><th class="p-3 text-right">Actual</th><th class="p-3 text-right">Liability</th><th class="p-3 text-left">Status</th></tr></thead><tbody>{% for x in review.transactions %}<tr class="border-t"><td class="p-3">{{ x.date }}</td><td class="p-3">{{ x.party }}</td><td class="p-3">{{ x.nature_ledger }}<div class="text-xs text-slate-500">{{ x.rule_name }} · {{ x.legacy_section }}</div></td><td class="p-3 text-right">{{ '%.2f'|format(x.taxable_base) }}</td><td class="p-3 text-right">{{ '%.2f'|format(x.expected_tds) }}</td><td class="p-3 text-right">{{ '%.2f'|format(x.actual_tds) }}</td><td class="p-3 text-right font-semibold">{{ '%.2f'|format(x.liability) }}</td><td class="p-3">{{ x.status }}</td></tr>{% endfor %}</tbody></table></div>{% endif %}{% if history %}<div class="rounded-2xl bg-white p-5 shadow-soft"><h2 class="font-semibold">TDS Analysis History</h2><div class="mt-3 overflow-x-auto"><table class="min-w-full text-sm"><tbody>{% for row in history %}<tr class="border-t"><td class="p-2">#{{ row.id }}</td><td class="p-2">{{ row.financial_year }}</td><td class="p-2">{{ row.period_from }} → {{ row.period_to }}</td><td class="p-2 text-right"><a class="font-semibold text-violet-700" href="/tools/tally/analysis/{{ row.id }}/download?client_id={{ selected_client.id }}&financial_year={{ row.financial_year }}&format=xlsx">Excel</a> · <a class="font-semibold text-violet-700" href="/tools/tally/analysis/{{ row.id }}/download?client_id={{ selected_client.id }}&financial_year={{ row.financial_year }}&format=pdf">PDF</a></td></tr>{% endfor %}</tbody></table></div></div>{% endif %}</div>
{% endblock %}