Files
arrr-erp/app/modules/accounting/templates/accounting/sales_income.html
T
2026-08-22 22:43:44 +05:30

160 lines
9.8 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 · Sales & Income · Phase 14</p>
<h1 class="mt-1 text-2xl font-semibold text-slate-900">Sales & Income Foundation</h1>
<p class="mt-1 max-w-4xl text-sm text-slate-500">Normalized outward transaction register with customer/GSTIN identity, historical customer/ledger learning, income-nature ranking and reviewer-confirmed sales ledger mapping. Phase 14 is review-only; Tally sales posting is not enabled yet.</p>
</div>
<div class="flex flex-wrap gap-2">
<a href="/tools/accounting/sales-learning{% if selected_client %}?client_id={{ selected_client.id }}{% endif %}" class="rounded-xl border border-emerald-300 bg-emerald-50 px-4 py-2 text-sm font-semibold text-emerald-800">Customer Intelligence</a>
<a href="/tools/tally{% 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">Back to Accounting</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-[1fr_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">
<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>
<div class="flex items-end"><button class="rounded-xl bg-brand-600 px-4 py-2 text-sm font-semibold text-white">Open Sales & Income</button></div>
</form>
</section>
{% if selected_client %}
<section class="rounded-2xl bg-white p-5 shadow-soft">
<h2 class="font-semibold text-slate-900">Import Outward Sales / Income</h2>
<p class="mt-1 text-sm text-slate-500">Upload CSV/XLS/XLSX exported from GSTR-1 working papers, billing software or another outward-sales source. Flexible common column names are detected automatically. Duplicate invoice fingerprints are skipped.</p>
<form method="post" action="/tools/accounting/sales-income/import" enctype="multipart/form-data" class="mt-4 grid gap-4 md:grid-cols-[220px_1fr_auto] md:items-end">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="hidden" name="client_id" value="{{ selected_client.id }}">
<label class="text-sm font-semibold">Source
<select name="source_type" class="mt-1 w-full rounded-xl border border-slate-300 bg-white px-3 py-2">
<option value="outward_import">Outward Sales Import</option>
<option value="gstr1">GSTR-1</option>
<option value="einvoice_outward">E-Invoice Outward</option>
<option value="ewaybill_outward">E-Way Bill Outward</option>
</select>
</label>
<label class="text-sm font-semibold">CSV / Excel file
<input type="file" name="file" accept=".csv,.xlsx,.xls,.xlsm" required class="mt-1 block w-full rounded-xl border border-slate-300 bg-white px-3 py-2 text-sm">
</label>
<button class="rounded-xl bg-slate-900 px-4 py-2 text-sm font-semibold text-white">Import</button>
</form>
</section>
<section class="rounded-2xl bg-white p-5 shadow-soft">
<form method="get" class="grid gap-3 md:grid-cols-5">
<input type="hidden" name="client_id" value="{{ selected_client.id }}">
<label class="text-xs font-semibold">Status
<select name="status" class="mt-1 w-full rounded-lg border border-slate-300 px-2 py-2">
{% for value,label in [('all','All'),('suggested','Suggested'),('review_required','Review Required'),('reviewed','Reviewed')] %}
<option value="{{ value }}" {% if status_filter==value %}selected{% endif %}>{{ label }}</option>
{% endfor %}
</select>
</label>
<label class="text-xs font-semibold md:col-span-2">Customer / GSTIN
<input name="customer" value="{{ customer_filter }}" class="mt-1 w-full rounded-lg border border-slate-300 px-2 py-2">
</label>
<label class="text-xs font-semibold">Return Period
<input name="period" value="{{ period_filter }}" placeholder="2026-07" class="mt-1 w-full rounded-lg border border-slate-300 px-2 py-2">
</label>
<div class="flex items-end"><button class="w-full rounded-lg border border-slate-300 px-3 py-2 text-sm font-semibold">Filter</button></div>
</form>
</section>
<section class="rounded-2xl bg-white shadow-soft">
<div class="border-b border-slate-200 px-5 py-4">
<h2 class="font-semibold">{{ selected_client.client_name }} · Sales & Income Register</h2>
<p class="text-sm text-slate-500">{{ total }} normalized outward transaction(s).</p>
</div>
<div class="divide-y divide-slate-100">
{% for row in rows %}
<article class="p-5">
<div class="grid gap-4 xl:grid-cols-12">
<div class="xl:col-span-3">
<div class="font-semibold">{{ row.invoice_date or 'No date' }} · {{ row.invoice_number or 'No invoice no.' }}</div>
<div class="mt-1 text-sm">{{ row.customer_name or 'Unnamed customer' }}</div>
<div class="text-xs text-slate-500">{{ row.customer_gstin or 'No GSTIN' }}</div>
<div class="mt-2 text-sm">{{ row.description_text or '—' }}</div>
<div class="mt-2 font-semibold">₹{{ '%.2f'|format(row.invoice_value) }}</div>
</div>
<div class="xl:col-span-3">
<div class="text-xs uppercase text-slate-500">First-pass suggestion</div>
<div class="mt-1 font-semibold">
{% for n in natures %}{% if n.id == row.suggested_nature_id %}{{ n.name }}{% endif %}{% endfor %}
</div>
<div class="text-sm">{{ row.suggested_confidence }}% confidence</div>
<div class="mt-2 text-xs text-slate-500">{{ row.suggestion_reason or '—' }}</div>
<div class="mt-2 text-xs text-slate-500">{{ row.source_type }} · {{ row.hsn_code or 'No HSN/SAC' }}</div>
</div>
<div class="xl:col-span-6">
{% if row.review_status != 'reviewed' %}
<form method="post" action="/tools/accounting/sales-income/{{ row.id }}/review" class="grid gap-2 md:grid-cols-2">
<input type="hidden" name="csrf_token" value="{{ csrf_token }}">
<input type="hidden" name="client_id" value="{{ selected_client.id }}">
<input type="hidden" name="status" value="{{ status_filter }}">
<input type="hidden" name="customer" value="{{ customer_filter }}">
<input type="hidden" name="period" value="{{ period_filter }}">
<input type="hidden" name="page" value="{{ page }}">
<input type="hidden" name="per_page" value="{{ per_page }}">
<label class="text-xs font-semibold">Sales / Income Nature
<select name="final_nature_id" required class="mt-1 w-full rounded-lg border border-slate-300 px-2 py-2">
{% for n in natures %}
<option value="{{ n.id }}" {% if n.id == row.suggested_nature_id %}selected{% endif %}>{{ n.name }}</option>
{% endfor %}
</select>
</label>
<label class="text-xs font-semibold">Client Tally Sales / Income Ledger
<input name="final_ledger_name" value="{{ row.suggested_ledger_name }}" placeholder="Reviewer maps existing Tally ledger" class="mt-1 w-full rounded-lg border border-slate-300 px-2 py-2">
</label>
<label class="text-xs font-semibold md:col-span-2">Review note
<input name="review_note" class="mt-1 w-full rounded-lg border border-slate-300 px-2 py-2">
</label>
<button class="rounded-lg bg-brand-600 px-3 py-2 text-sm font-semibold text-white md:col-span-2">Confirm Sales / Income Treatment</button>
</form>
{% else %}
<div class="rounded-xl border border-emerald-200 bg-emerald-50 p-3 text-sm text-emerald-800">
<strong>Reviewed.</strong>
{% for n in natures %}{% if n.id == row.final_nature_id %}{{ n.name }}{% endif %}{% endfor %}
{% if row.final_ledger_name %} · {{ row.final_ledger_name }}{% endif %}
</div>
{% endif %}
</div>
</div>
</article>
{% else %}
<div class="p-10 text-center text-sm text-slate-500">No Sales & Income records yet. Import an outward-sales CSV/Excel file above.</div>
{% endfor %}
</div>
{% if pages > 1 %}
<div class="flex items-center justify-between border-t border-slate-200 p-4 text-sm">
<span>Page {{ page }} of {{ pages }}</span>
<div class="flex gap-2">
{% if page > 1 %}
<a class="rounded-lg border border-slate-300 px-3 py-1" href="?client_id={{ selected_client.id }}&status={{ status_filter }}&customer={{ customer_filter }}&period={{ period_filter }}&page={{ page-1 }}&per_page={{ per_page }}">Previous</a>
{% endif %}
{% if page < pages %}
<a class="rounded-lg border border-slate-300 px-3 py-1" href="?client_id={{ selected_client.id }}&status={{ status_filter }}&customer={{ customer_filter }}&period={{ period_filter }}&page={{ page+1 }}&per_page={{ per_page }}">Next</a>
{% endif %}
</div>
</div>
{% endif %}
</section>
{% endif %}
</div>
{% endblock %}