Add Phase 11 bank to Tally with multi-bank contra intelligence

This commit is contained in:
A R R R Associates
2026-08-22 19:59:40 +05:30
parent 215ad2c6c6
commit 8748ee9539
16 changed files with 1140 additions and 28 deletions
@@ -3,7 +3,7 @@
<div class="mx-auto max-w-6xl space-y-6">
<div class="rounded-2xl border border-slate-200 bg-white p-6 shadow-soft">
<div class="flex flex-wrap items-start justify-between gap-3">
<div><h1 class="text-2xl font-bold text-slate-900">Bank Statement Analyzer</h1><p class="mt-2 text-sm text-slate-600">Upload supported PDF statements. Up to three analyses run globally at one time; additional jobs are queued safely.</p></div>
<div><h1 class="text-2xl font-bold text-slate-900">Bank Statement Analyzer</h1><p class="mt-2 text-sm text-slate-600">Upload one or several PDF statements for the same client. Multiple bank accounts can be analysed together so equal-and-opposite inter-bank transfers can be identified as probable contra. Up to three analyses run globally at one time; additional jobs are queued safely.</p></div>
<a href="/tools/bank-statement-analyzer/jobs" class="rounded-xl border border-slate-300 px-4 py-2 text-sm font-semibold text-slate-700 hover:bg-slate-50">My Analysis Jobs</a>
</div>
</div>
@@ -19,7 +19,7 @@
<div><label class="mb-1 block text-sm font-semibold text-slate-700">Account number override <span class="font-normal text-slate-400">(optional)</span></label><input name="account_number" class="w-full rounded-xl border border-slate-300 px-3 py-2 text-sm" placeholder="Use only when statement extraction needs correction"></div>
</div>
<div class="mt-5 rounded-xl border border-slate-200 bg-slate-50 p-4"><label class="flex items-start gap-3"><input type="checkbox" name="enable_classification" value="1" {% if classification_enabled %}checked{% endif %} class="mt-1 h-4 w-4 rounded border-slate-300"><span><span class="block text-sm font-semibold text-slate-800">Enable narration-based transaction classification</span><span class="mt-1 block text-xs text-slate-500">Adds category, party, review and draft financial helper sheets. Final classification must be verified with books and supporting records.</span></span></label></div>
<div class="mt-5"><label class="mb-1 block text-sm font-semibold text-slate-700">PDF bank statements</label><input type="file" name="statements" accept="application/pdf,.pdf" multiple required class="block w-full rounded-xl border border-slate-300 bg-white px-3 py-3 text-sm"></div>
<div class="mt-5 rounded-xl border border-brand-200 bg-brand-50 p-4 text-sm text-slate-700"><strong>Multi-bank contra detection:</strong> when the client has more than one bank account, upload all relevant statements in the same analysis job. The analyzer pairs only conservative equal-and-opposite transfers across different account numbers and keeps every pair reviewable.</div><div class="mt-5"><label class="mb-1 block text-sm font-semibold text-slate-700">PDF bank statements</label><input type="file" name="statements" accept="application/pdf,.pdf" multiple required class="block w-full rounded-xl border border-slate-300 bg-white px-3 py-3 text-sm"></div>
<div class="mt-5 rounded-xl bg-slate-50 p-4 text-sm text-slate-600"><div class="font-semibold text-slate-800">Queue limits</div><div class="mt-1">Maximum three processing jobs across all users. Each user may have up to three queued or processing jobs. Completed workbooks and original uploaded statements remain available for 24 hours. Failed-job statements are also retained for 24 hours for debugging.</div></div>
<div class="mt-6 flex flex-wrap gap-3"><button class="rounded-xl bg-brand-600 px-5 py-2.5 text-sm font-semibold text-white hover:bg-brand-700">Submit Analysis</button></div>
</form>
@@ -30,7 +30,7 @@
<div class="mt-5 grid gap-4 sm:grid-cols-2 lg:grid-cols-4"><div class="rounded-xl bg-slate-50 p-4"><div class="text-xs text-slate-500">Files</div><div class="mt-1 text-lg font-bold">{{ active_job.file_count }}</div></div><div class="rounded-xl bg-slate-50 p-4"><div class="text-xs text-slate-500">Queue position</div><div id="queue-position" class="mt-1 text-lg font-bold">{{ active_job.queue_position or '—' }}</div></div><div class="rounded-xl bg-slate-50 p-4"><div class="text-xs text-slate-500">Estimated wait</div><div id="estimated-wait" class="mt-1 text-sm font-bold">{{ active_job.estimated_wait or '—' }}</div></div><div class="rounded-xl bg-slate-50 p-4"><div class="text-xs text-slate-500">Progress</div><div id="progress-text" class="mt-1 text-lg font-bold">{{ active_job.progress_percent }}%</div></div></div>
<div class="mt-4 h-2 overflow-hidden rounded-full bg-slate-200"><div id="progress-bar" class="h-full bg-brand-600 transition-all" style="width: {{ active_job.progress_percent }}%"></div></div>
{% if active_job.status == 'completed' %}
<div class="mt-6 rounded-xl border border-emerald-200 bg-emerald-50 p-5"><h3 class="font-bold text-emerald-900">Analysis completed</h3><div class="mt-4 grid gap-3 sm:grid-cols-2 lg:grid-cols-4"><div><div class="text-xs text-emerald-700">Statements</div><div class="font-bold">{{ active_job.summary.statement_count or 0 }}</div></div><div><div class="text-xs text-emerald-700">Transactions extracted</div><div class="font-bold">{{ active_job.summary.rows_extracted or 0 }}</div></div><div><div class="text-xs text-emerald-700">Exact duplicates</div><div class="font-bold">{{ active_job.summary.exact_duplicate_rows or 0 }}</div></div><div><div class="text-xs text-emerald-700">Review items</div><div class="font-bold">{{ active_job.summary.review_items or 0 }}</div></div></div><div class="mt-5 flex flex-wrap gap-3"><a href="/tools/bank-statement-analyzer/jobs/{{ active_job.id }}/download" class="rounded-xl bg-emerald-700 px-5 py-2.5 text-sm font-semibold text-white">Download Excel</a>{% for file in active_job.original_files %}<a href="/tools/bank-statement-analyzer/jobs/{{ active_job.id }}/statements/{{ file.index }}/download" class="rounded-xl border border-emerald-300 bg-white px-5 py-2.5 text-sm font-semibold text-emerald-800">Download Statement {{ file.index }}</a>{% endfor %}<a href="/tools/bank-statement-analyzer" class="rounded-xl border border-emerald-300 bg-white px-5 py-2.5 text-sm font-semibold text-emerald-800">Analyze Another Bank</a></div><p class="mt-3 text-xs text-emerald-700">The workbook and original statement{{ 's' if active_job.file_count != 1 else '' }} remain available until {{ active_job.expires_at or '24 hours after completion' }}.</p></div>
<div class="mt-6 rounded-xl border border-emerald-200 bg-emerald-50 p-5"><h3 class="font-bold text-emerald-900">Analysis completed</h3><div class="mt-4 grid gap-3 sm:grid-cols-2 lg:grid-cols-4"><div><div class="text-xs text-emerald-700">Statements</div><div class="font-bold">{{ active_job.summary.statement_count or 0 }}</div></div><div><div class="text-xs text-emerald-700">Transactions extracted</div><div class="font-bold">{{ active_job.summary.rows_extracted or 0 }}</div></div><div><div class="text-xs text-emerald-700">Exact duplicates</div><div class="font-bold">{{ active_job.summary.exact_duplicate_rows or 0 }}</div></div><div><div class="text-xs text-emerald-700">Review items</div><div class="font-bold">{{ active_job.summary.review_items or 0 }}</div></div><div><div class="text-xs text-emerald-700">Inter-bank contra pairs</div><div class="font-bold">{{ active_job.summary.contra_pairs or 0 }}</div></div></div><div class="mt-5 flex flex-wrap gap-3"><a href="/tools/bank-statement-analyzer/jobs/{{ active_job.id }}/download" class="rounded-xl bg-emerald-700 px-5 py-2.5 text-sm font-semibold text-white">Download Excel</a>{% for file in active_job.original_files %}<a href="/tools/bank-statement-analyzer/jobs/{{ active_job.id }}/statements/{{ file.index }}/download" class="rounded-xl border border-emerald-300 bg-white px-5 py-2.5 text-sm font-semibold text-emerald-800">Download Statement {{ file.index }}</a>{% endfor %}<a href="/tools/bank-statement-analyzer" class="rounded-xl border border-emerald-300 bg-white px-5 py-2.5 text-sm font-semibold text-emerald-800">Analyze Another Bank</a></div><p class="mt-3 text-xs text-emerald-700">The workbook and original statement{{ 's' if active_job.file_count != 1 else '' }} remain available until {{ active_job.expires_at or '24 hours after completion' }}.</p></div>
{% elif active_job.status == 'failed' %}<div class="mt-5 rounded-xl border border-red-200 bg-red-50 p-4 text-sm text-red-800"><strong>Analysis failed.</strong><div class="mt-1">{{ active_job.error_message }}</div>{% if active_job.original_files %}<div class="mt-4 flex flex-wrap gap-3">{% for file in active_job.original_files %}<a href="/tools/bank-statement-analyzer/jobs/{{ active_job.id }}/statements/{{ file.index }}/download" class="rounded-xl border border-red-300 bg-white px-4 py-2 text-sm font-semibold text-red-800">Download Statement {{ file.index }}</a>{% endfor %}</div><p class="mt-3 text-xs text-red-700">Original statement{{ 's are' if active_job.file_count != 1 else ' is' }} retained until {{ active_job.expires_at or '24 hours after failure' }} for debugging.</p>{% endif %}<a href="/tools/bank-statement-analyzer" class="mt-3 inline-block font-semibold underline">Analyze another statement</a></div>
{% else %}<div id="live-message" class="mt-5 rounded-xl border border-blue-200 bg-blue-50 p-4 text-sm text-blue-800">{% if active_job.status == 'queued' %}Your job is queued. You may safely leave this page and return through My Analysis Jobs.{% else %}Your statements are being processed.{% endif %}</div>{% endif %}
</section>