245 lines
15 KiB
HTML
245 lines
15 KiB
HTML
{% 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-brand-600">Accounting Engine · Phase 18</p>
|
|
<h1 class="mt-1 text-2xl font-semibold text-slate-900">Automatic Accounting Preparation</h1>
|
|
<p class="mt-1 max-w-5xl text-sm text-slate-500">
|
|
Create native Tally voucher drafts automatically from existing Bank Analyzer and E-Way Bill source data. Purchase and Sales drafts retain stock-item level quantity, unit, rate, HSN and taxable value for native Tally inventory vouchers.
|
|
</p>
|
|
</div>
|
|
<div class="flex flex-wrap gap-2">
|
|
<a href="/tools/accounting/voucher-engine{% if selected_client %}?client_id={{ selected_client.id }}{% endif %}" class="rounded-xl border border-slate-300 bg-white px-4 py-2 text-sm font-semibold">Voucher Review Queue</a>
|
|
<a href="/tools/accounting/chart-of-accounts{% if selected_client %}?client_id={{ selected_client.id }}{% endif %}" class="rounded-xl border border-slate-300 bg-white px-4 py-2 text-sm font-semibold">Chart of Accounts</a>
|
|
</div>
|
|
</div>
|
|
|
|
{% if message %}<div class="rounded-xl border border-emerald-200 bg-emerald-50 p-3 text-sm text-emerald-800">{{ message }}</div>{% endif %}
|
|
{% if error %}<div class="rounded-xl border border-red-200 bg-red-50 p-3 text-sm text-red-800">{{ error }}</div>{% endif %}
|
|
|
|
<section class="rounded-2xl bg-white p-5 shadow-soft">
|
|
<form method="get" class="grid gap-4 md:grid-cols-2 xl:grid-cols-6">
|
|
<label class="text-xs font-semibold xl:col-span-2">ERP Client
|
|
<select name="client_id" required class="mt-1 w-full rounded-lg border border-slate-300 bg-white px-3 py-2">
|
|
<option value="">Select client</option>
|
|
{% for c in clients %}
|
|
<option value="{{ c.id }}" {% if selected_client and selected_client.id==c.id %}selected{% endif %}>{{ c.client_name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</label>
|
|
|
|
<label class="text-xs font-semibold xl:col-span-2">Tally Company / Chart of Accounts
|
|
<select name="tally_guid" class="mt-1 w-full rounded-lg border border-slate-300 bg-white px-3 py-2">
|
|
<option value="">Select company</option>
|
|
{% for c in company_options %}
|
|
<option value="{{ c.guid }}" {% if selected_tally_guid==c.guid %}selected{% endif %}>{{ c.name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</label>
|
|
|
|
<label class="text-xs font-semibold">From
|
|
<input type="date" name="from_date" value="{{ from_date }}" class="mt-1 w-full rounded-lg border border-slate-300 px-3 py-2">
|
|
</label>
|
|
|
|
<label class="text-xs font-semibold">To
|
|
<input type="date" name="to_date" value="{{ to_date }}" class="mt-1 w-full rounded-lg border border-slate-300 px-3 py-2">
|
|
</label>
|
|
|
|
<div class="xl:col-span-6 flex justify-end">
|
|
<button class="rounded-xl bg-brand-600 px-5 py-2 text-sm font-semibold text-white">Load Automatic Sources</button>
|
|
</div>
|
|
</form>
|
|
</section>
|
|
|
|
{% if selected_client and selected_tally_guid %}
|
|
<section class="grid gap-4 lg:grid-cols-3">
|
|
<div class="rounded-2xl border border-emerald-200 bg-emerald-50/50 p-5">
|
|
<p class="text-xs font-semibold uppercase tracking-wider text-emerald-700">Bank Statements</p>
|
|
<h2 class="mt-1 font-semibold">Receipt / Payment / Contra</h2>
|
|
<p class="mt-1 text-sm text-slate-600">Bank Analyzer rows are converted into native Receipt, Payment or Contra voucher drafts. The bank ledger is chosen from the client's classified Chart of Accounts.</p>
|
|
</div>
|
|
<div class="rounded-2xl border border-blue-200 bg-blue-50/50 p-5">
|
|
<p class="text-xs font-semibold uppercase tracking-wider text-blue-700">E-Way Bill · Inward</p>
|
|
<h2 class="mt-1 font-semibold">Stock-item Purchase</h2>
|
|
<p class="mt-1 text-sm text-slate-600">Each invoice retains every item, HSN, quantity, unit, rate, taxable value and tax amounts and creates a native Purchase voucher draft.</p>
|
|
</div>
|
|
<div class="rounded-2xl border border-violet-200 bg-violet-50/50 p-5">
|
|
<p class="text-xs font-semibold uppercase tracking-wider text-violet-700">E-Way Bill · Outward</p>
|
|
<h2 class="mt-1 font-semibold">Stock-item Sales</h2>
|
|
<p class="mt-1 text-sm text-slate-600">Outward invoices create native Sales voucher drafts with item-wise inventory allocations and output-tax ledger lines.</p>
|
|
</div>
|
|
</section>
|
|
|
|
<section class="rounded-2xl bg-white shadow-soft">
|
|
<div class="flex flex-wrap items-center justify-between gap-3 border-b border-slate-200 p-5">
|
|
<div>
|
|
<h2 class="font-semibold">Bank Analyzer Transactions</h2>
|
|
<p class="text-sm text-slate-500">One click creates the proposed Receipt / Payment / Contra draft. Posting remains subject to the common review and Tally preflight controls.</p>
|
|
</div>
|
|
<form method="get" class="flex flex-wrap gap-2">
|
|
<input type="hidden" name="client_id" value="{{ selected_client.id }}">
|
|
<input type="hidden" name="tally_guid" value="{{ selected_tally_guid }}">
|
|
<input type="hidden" name="from_date" value="{{ from_date }}">
|
|
<input type="hidden" name="to_date" value="{{ to_date }}">
|
|
<select name="bank_source" class="rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm">
|
|
{% for source in sources.bank %}
|
|
<option value="{{ source.table_name }}" {% if selected_bank_source==source.table_name %}selected{% endif %}>{{ source.table_name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
<button class="rounded-lg border border-slate-300 px-3 py-2 text-sm font-semibold">Change Source</button>
|
|
</form>
|
|
</div>
|
|
|
|
{% if not sources.bank %}
|
|
<div class="p-8 text-center text-slate-500">
|
|
No existing Bank Analyzer transaction table containing client/date/narration/amount fields was discovered in the current ERP schema. Existing Bank Analyzer data has not been changed.
|
|
</div>
|
|
{% elif not bank_rows %}
|
|
<div class="p-8 text-center text-slate-500">No Bank Analyzer transactions were found for the selected client/period.</div>
|
|
{% else %}
|
|
<div class="overflow-x-auto">
|
|
<table class="min-w-full text-sm">
|
|
<thead>
|
|
<tr class="bg-slate-50 text-left text-xs uppercase text-slate-500">
|
|
<th class="px-4 py-3">Date</th>
|
|
<th class="px-4 py-3">Narration / Party</th>
|
|
<th class="px-4 py-3">Direction</th>
|
|
<th class="px-4 py-3 text-right">Amount</th>
|
|
<th class="px-4 py-3">Bank/Cash Ledger</th>
|
|
<th class="px-4 py-3">Action</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for row in bank_rows %}
|
|
<tr class="border-t border-slate-100 align-top">
|
|
<td class="px-4 py-3 whitespace-nowrap">{{ row.date or '-' }}</td>
|
|
<td class="px-4 py-3">
|
|
<div class="font-semibold">{{ row.party or row.narration or '-' }}</div>
|
|
{% if row.party and row.narration %}<div class="mt-1 max-w-xl text-xs text-slate-500">{{ row.narration }}</div>{% endif %}
|
|
{% if row.category %}<div class="mt-1 text-xs text-slate-500">Category: {{ row.category }}</div>{% endif %}
|
|
{% if row.reference %}<div class="text-xs text-slate-500">Ref: {{ row.reference }}</div>{% endif %}
|
|
</td>
|
|
<td class="px-4 py-3"><span class="rounded-full px-2 py-1 text-xs font-semibold {% if row.direction=='DEBIT' %}bg-amber-100 text-amber-800{% else %}bg-emerald-100 text-emerald-800{% endif %}">{{ row.direction }}</span></td>
|
|
<td class="px-4 py-3 text-right font-semibold">₹{{ '%.2f'|format(row.amount) }}</td>
|
|
<td class="px-4 py-3">
|
|
<form method="post" action="/tools/accounting/voucher-engine/automatic/bank/draft" class="flex min-w-[320px] gap-2">
|
|
<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="source_table" value="{{ row.source_table }}">
|
|
<input type="hidden" name="source_id" value="{{ row.source_id }}">
|
|
<select name="bank_ledger_name" required class="min-w-[190px] flex-1 rounded-lg border border-slate-300 bg-white px-2 py-2 text-xs">
|
|
<option value="">Select Bank/Cash ledger</option>
|
|
{% for ledger in bank_ledgers %}
|
|
<option value="{{ ledger.name }}">{{ ledger.name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
<button class="rounded-lg bg-slate-900 px-3 py-2 text-xs font-semibold text-white">Create Draft</button>
|
|
</form>
|
|
</td>
|
|
<td class="px-4 py-3 text-xs text-slate-500">{% if row.contra_hint %}Contra hint detected{% else %}Auto ledger matching from party/category{% endif %}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
{% endif %}
|
|
</section>
|
|
|
|
<section class="rounded-2xl bg-white shadow-soft">
|
|
<div class="flex flex-wrap items-center justify-between gap-3 border-b border-slate-200 p-5">
|
|
<div>
|
|
<h2 class="font-semibold">E-Way Bill Purchase / Sales Invoices</h2>
|
|
<p class="text-sm text-slate-500">Invoices are grouped by E-Way Bill + invoice + party. Every underlying item remains separate in the voucher draft.</p>
|
|
</div>
|
|
<form method="get" class="flex flex-wrap gap-2">
|
|
<input type="hidden" name="client_id" value="{{ selected_client.id }}">
|
|
<input type="hidden" name="tally_guid" value="{{ selected_tally_guid }}">
|
|
<input type="hidden" name="from_date" value="{{ from_date }}">
|
|
<input type="hidden" name="to_date" value="{{ to_date }}">
|
|
<select name="eway_source" class="rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm">
|
|
{% for source in sources.eway %}
|
|
<option value="{{ source.table_name }}" {% if selected_eway_source==source.table_name %}selected{% endif %}>{{ source.table_name }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
<select name="direction" class="rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm">
|
|
<option value="" {% if not direction %}selected{% endif %}>Purchase + Sales</option>
|
|
<option value="PURCHASE" {% if direction=='PURCHASE' %}selected{% endif %}>Purchase / Inward</option>
|
|
<option value="SALES" {% if direction=='SALES' %}selected{% endif %}>Sales / Outward</option>
|
|
</select>
|
|
<button class="rounded-lg border border-slate-300 px-3 py-2 text-sm font-semibold">Apply</button>
|
|
</form>
|
|
</div>
|
|
|
|
{% if not sources.eway %}
|
|
<div class="p-8 text-center text-slate-500">
|
|
No existing E-Way Bill item table containing E-Way Bill number, item description and taxable value was discovered in the current ERP schema. Existing E-Way Bill features have not been modified.
|
|
</div>
|
|
{% elif not eway_invoices %}
|
|
<div class="p-8 text-center text-slate-500">No E-Way Bill item invoices were found for this client/period/filter.</div>
|
|
{% else %}
|
|
<div class="divide-y divide-slate-100">
|
|
{% for inv in eway_invoices %}
|
|
<article class="p-5">
|
|
<div class="flex flex-wrap items-start justify-between gap-4">
|
|
<div>
|
|
<div class="flex flex-wrap gap-2">
|
|
<span class="rounded-full px-2 py-1 text-xs font-semibold {% if inv.direction=='PURCHASE' %}bg-blue-100 text-blue-800{% elif inv.direction=='SALES' %}bg-violet-100 text-violet-800{% else %}bg-slate-100{% endif %}">{{ inv.direction }}</span>
|
|
<span class="rounded-full bg-slate-100 px-2 py-1 text-xs font-semibold">{{ inv.items|length }} stock item(s)</span>
|
|
</div>
|
|
<h3 class="mt-2 font-semibold">{{ inv.party_name or 'Party not available' }}</h3>
|
|
<p class="text-sm text-slate-500">GSTIN {{ inv.party_gstin or '-' }} · Invoice {{ inv.invoice_no or '-' }} · {{ inv.invoice_date or '-' }} · EWB {{ inv.eway_bill_no or '-' }}</p>
|
|
</div>
|
|
<div class="text-right">
|
|
<div class="font-semibold">Taxable ₹{{ '%.2f'|format(inv.taxable_value) }}</div>
|
|
<div class="text-xs text-slate-500">CGST {{ '%.2f'|format(inv.cgst) }} · SGST {{ '%.2f'|format(inv.sgst) }} · IGST {{ '%.2f'|format(inv.igst) }} · Cess {{ '%.2f'|format(inv.cess) }}</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="mt-4 overflow-x-auto rounded-xl border border-slate-200">
|
|
<table class="min-w-full text-xs">
|
|
<thead><tr class="bg-slate-50 text-left uppercase text-slate-500"><th class="px-3 py-2">Stock Item / Description</th><th class="px-3 py-2">HSN</th><th class="px-3 py-2 text-right">Qty</th><th class="px-3 py-2">Unit</th><th class="px-3 py-2 text-right">Rate</th><th class="px-3 py-2 text-right">Taxable</th></tr></thead>
|
|
<tbody>
|
|
{% for item in inv.items %}
|
|
<tr class="border-t border-slate-100">
|
|
<td class="px-3 py-2 font-semibold">{{ item.item_name or '-' }}</td>
|
|
<td class="px-3 py-2">{{ item.hsn or '-' }}</td>
|
|
<td class="px-3 py-2 text-right">{{ item.quantity }}</td>
|
|
<td class="px-3 py-2">{{ item.unit or '-' }}</td>
|
|
<td class="px-3 py-2 text-right">{{ '%.4f'|format(item.rate) }}</td>
|
|
<td class="px-3 py-2 text-right">₹{{ '%.2f'|format(item.taxable_value) }}</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<form method="post" action="/tools/accounting/voucher-engine/automatic/eway/draft" class="mt-4 flex justify-end">
|
|
<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="source_table" value="{{ inv.source_table }}">
|
|
<input type="hidden" name="direction" value="{{ inv.direction }}">
|
|
<input type="hidden" name="eway_bill_no" value="{{ inv.eway_bill_no }}">
|
|
<input type="hidden" name="invoice_no" value="{{ inv.invoice_no }}">
|
|
<input type="hidden" name="invoice_date" value="{{ inv.invoice_date }}">
|
|
<input type="hidden" name="party_gstin" value="{{ inv.party_gstin }}">
|
|
<input type="hidden" name="party_name" value="{{ inv.party_name }}">
|
|
<button class="rounded-xl bg-brand-600 px-4 py-2 text-sm font-semibold text-white">Create Stock-item {{ inv.direction|title }} Draft</button>
|
|
</form>
|
|
</article>
|
|
{% endfor %}
|
|
</div>
|
|
{% endif %}
|
|
</section>
|
|
|
|
<section class="rounded-2xl border border-slate-200 bg-slate-50 p-5">
|
|
<h2 class="font-semibold">Manual entry remains only as a fallback</h2>
|
|
<p class="mt-1 text-sm text-slate-600">Manual / adjustment voucher creation has not been removed. It remains useful for provisions, accruals, depreciation, reclassification, audit adjustments and source transactions that cannot yet be resolved automatically.</p>
|
|
<a href="/tools/accounting/voucher-engine?client_id={{ selected_client.id }}" class="mt-3 inline-flex rounded-lg border border-slate-300 bg-white px-3 py-2 text-sm font-semibold">Open Manual / Review Voucher Engine</a>
|
|
</section>
|
|
{% endif %}
|
|
</div>
|
|
{% endblock %}
|