Transaction Details now renders each voucher as a paired Dr/Cr journal entry with a derived contra account and a Balanced status chip, so both sides of a transaction are visible at a glance for reconciliation. Adds a shared cashier-export.ts (mirrors the Investment module's exporter) and an Export to Excel button producing a Summary + Transaction Details workbook, plus a Branch Breakup sheet for Head Office consolidated view.
293 lines
10 KiB
HTML
293 lines
10 KiB
HTML
<!--
|
|
Copyright since 2025 Mifos Initiative
|
|
|
|
This Source Code Form is subject to the terms of the Mozilla Public
|
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
-->
|
|
|
|
<div class="pg">
|
|
<header class="pg-head">
|
|
<div>
|
|
<div class="pg-eyebrow">SUB LEDGER · TRANSACTIONS · {{ scopeName | uppercase }}</div>
|
|
<h1 class="pg-title">Cash / Clearing / Transfer - Summary Report</h1>
|
|
<p class="pg-sub">
|
|
Opening, credit, debit and closing position across Cash, Transfer, Clearing and Digital channels as on
|
|
{{ asOnDate }}.
|
|
</p>
|
|
</div>
|
|
<div class="pg-toolbar">
|
|
@if (isHeadOffice) {
|
|
<label class="pg-field">
|
|
<span>Branch</span>
|
|
<select class="pg-select" [ngModel]="selectedBranchCode" (ngModelChange)="setBranch($event)">
|
|
<option value="ALL">All Branches (Consolidated)</option>
|
|
@for (b of branches; track b.code) {
|
|
<option [value]="b.code">{{ b.name }}</option>
|
|
}
|
|
</select>
|
|
</label>
|
|
}
|
|
<button type="button" class="pg-btn" [class.pg-btn--active]="showDetails" (click)="toggleDetails()">
|
|
{{ showDetails ? 'Summary View' : 'Transaction Details' }}
|
|
</button>
|
|
<button type="button" class="pg-btn pg-btn--ghost" [disabled]="generating" (click)="exportExcel()">
|
|
{{ generating ? 'Exporting…' : 'Export to Excel' }}
|
|
</button>
|
|
</div>
|
|
</header>
|
|
|
|
<div class="cctr-grand-summary">
|
|
<div class="cctr-grand-summary__item">
|
|
<span class="cctr-grand-summary__label">Opening</span>
|
|
<span class="cctr-grand-summary__value">₹{{ grandOpening | number: '1.2-2' }}</span>
|
|
</div>
|
|
<div class="cctr-grand-summary__item">
|
|
<span class="cctr-grand-summary__label">Credit</span>
|
|
<span class="cctr-grand-summary__value col-in">₹{{ grandCredit | number: '1.2-2' }}</span>
|
|
</div>
|
|
<div class="cctr-grand-summary__item">
|
|
<span class="cctr-grand-summary__label">Debit</span>
|
|
<span class="cctr-grand-summary__value col-out">₹{{ grandDebit | number: '1.2-2' }}</span>
|
|
</div>
|
|
<div class="cctr-grand-summary__item">
|
|
<span class="cctr-grand-summary__label">Closing</span>
|
|
<span class="cctr-grand-summary__value">₹{{ grandClosing | number: '1.2-2' }}</span>
|
|
</div>
|
|
</div>
|
|
|
|
@if (isHeadOffice && selectedBranchCode === 'ALL') {
|
|
<div class="pg-card">
|
|
<div class="pos-section-label">Branch-wise Break-up — click a branch to drill in</div>
|
|
<table class="pg-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Branch</th>
|
|
<th class="num">Opening</th>
|
|
<th class="num col-in">Credit</th>
|
|
<th class="num col-out">Debit</th>
|
|
<th class="num col-net">Closing</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (b of branchBreakup; track b.code) {
|
|
<tr class="cctr-branch-row" (click)="setBranch(b.code)">
|
|
<td>{{ b.name }}</td>
|
|
<td class="num">₹{{ b.opening | number: '1.2-2' }}</td>
|
|
<td class="num col-in">₹{{ b.credit | number: '1.2-2' }}</td>
|
|
<td class="num col-out">₹{{ b.debit | number: '1.2-2' }}</td>
|
|
<td class="num col-net">₹{{ b.closing | number: '1.2-2' }}</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
<tfoot>
|
|
<tr class="cctr-total-row">
|
|
<td>All Branches</td>
|
|
<td class="num">₹{{ grandOpening | number: '1.2-2' }}</td>
|
|
<td class="num">₹{{ grandCredit | number: '1.2-2' }}</td>
|
|
<td class="num">₹{{ grandDebit | number: '1.2-2' }}</td>
|
|
<td class="num">₹{{ grandClosing | number: '1.2-2' }}</td>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
</div>
|
|
}
|
|
|
|
<div class="cctr-tabs">
|
|
<button
|
|
type="button"
|
|
class="pg-btn pg-btn--ghost"
|
|
[class.pg-btn--active]="activeTab === 'cash'"
|
|
(click)="setTab('cash')"
|
|
>
|
|
Cash
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="pg-btn pg-btn--ghost"
|
|
[class.pg-btn--active]="activeTab === 'transfer'"
|
|
(click)="setTab('transfer')"
|
|
>
|
|
Transfer
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="pg-btn pg-btn--ghost"
|
|
[class.pg-btn--active]="activeTab === 'clearing'"
|
|
(click)="setTab('clearing')"
|
|
>
|
|
Clearing
|
|
</button>
|
|
<button
|
|
type="button"
|
|
class="pg-btn pg-btn--ghost"
|
|
[class.pg-btn--active]="activeTab === 'digital'"
|
|
(click)="setTab('digital')"
|
|
>
|
|
Digital
|
|
</button>
|
|
</div>
|
|
|
|
<!-- Summary (Opening | Credit | Debit | Closing) -->
|
|
@if (!showDetails) {
|
|
<div class="pg-card">
|
|
@if (activeTab === 'digital') {
|
|
<div class="pos-section-label">RTGS · NEFT · UPI · ATM · NACH — Overall Position</div>
|
|
}
|
|
<table class="pg-table">
|
|
<thead>
|
|
<tr>
|
|
@if (activeTab !== 'digital') {
|
|
<th>GL Code</th>
|
|
}
|
|
<th>Particulars</th>
|
|
<th class="num">Opening</th>
|
|
<th class="num col-in">Credit</th>
|
|
<th class="num col-out">Debit</th>
|
|
<th class="num col-net">Closing</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (r of rowsForActiveTab; track r.code) {
|
|
<tr>
|
|
@if (activeTab !== 'digital') {
|
|
<td>
|
|
<span class="pg-chip">{{ r.code }}</span>
|
|
</td>
|
|
}
|
|
<td>{{ r.name }}</td>
|
|
<td class="num">₹{{ r.opening | number: '1.2-2' }}</td>
|
|
<td class="num col-in">₹{{ rowCredit(r, txnsForActiveTab) | number: '1.2-2' }}</td>
|
|
<td class="num col-out">₹{{ rowDebit(r, txnsForActiveTab) | number: '1.2-2' }}</td>
|
|
<td class="num col-net">₹{{ closing(r, txnsForActiveTab) | number: '1.2-2' }}</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
<tfoot>
|
|
<tr class="cctr-total-row">
|
|
<td [attr.colspan]="activeTab !== 'digital' ? 2 : 1">Total</td>
|
|
<td class="num">₹{{ total(rowsForActiveTab, txnsForActiveTab, 'opening') | number: '1.2-2' }}</td>
|
|
<td class="num">₹{{ total(rowsForActiveTab, txnsForActiveTab, 'credit') | number: '1.2-2' }}</td>
|
|
<td class="num">₹{{ total(rowsForActiveTab, txnsForActiveTab, 'debit') | number: '1.2-2' }}</td>
|
|
<td class="num">₹{{ totalClosing(rowsForActiveTab, txnsForActiveTab) | number: '1.2-2' }}</td>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
</div>
|
|
}
|
|
|
|
<!-- Transaction Details (all txns for the selected category, optionally filtered by GL/channel) -->
|
|
@if (showDetails) {
|
|
@if (rowsForActiveTab.length > 1) {
|
|
<div class="cctr-tabs">
|
|
<button
|
|
type="button"
|
|
class="pg-btn pg-btn--ghost"
|
|
[class.pg-btn--active]="glFilter === null"
|
|
(click)="setGlFilter(null)"
|
|
>
|
|
All
|
|
</button>
|
|
@for (r of rowsForActiveTab; track r.code) {
|
|
<button
|
|
type="button"
|
|
class="pg-btn pg-btn--ghost"
|
|
[class.pg-btn--active]="glFilter === r.code"
|
|
(click)="setGlFilter(r.code)"
|
|
>
|
|
{{ filterLabel(r) }}
|
|
</button>
|
|
}
|
|
</div>
|
|
}
|
|
|
|
<div class="pg-card">
|
|
<div class="pos-section-label">
|
|
{{
|
|
activeTab === 'cash'
|
|
? 'Cash'
|
|
: activeTab === 'transfer'
|
|
? 'Transfer'
|
|
: activeTab === 'clearing'
|
|
? 'Clearing'
|
|
: 'Digital'
|
|
}}
|
|
— Transaction Details (Full Double Entry)
|
|
@if (glFilter !== null) {
|
|
· {{ glFilter }}
|
|
}
|
|
</div>
|
|
<table class="pg-table cctr-journal">
|
|
<thead>
|
|
<tr>
|
|
<th>Date</th>
|
|
<th>Voucher / Ref No</th>
|
|
<th>Dr / Cr</th>
|
|
<th>GL / Account</th>
|
|
<th class="num col-out">Debit</th>
|
|
<th class="num col-in">Credit</th>
|
|
<th>Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (t of filteredTxns; track t.voucherNo) {
|
|
<tr class="cctr-journal-row cctr-journal-row--first">
|
|
<td>{{ asOnDate }}</td>
|
|
<td>
|
|
<span class="pg-chip">{{ display(t.voucherNo) }}</span>
|
|
</td>
|
|
<td><span class="cctr-drcr cctr-drcr--dr">Dr</span></td>
|
|
<td>
|
|
@if (t.debit > 0) {
|
|
<span class="pg-chip">{{ t.glCode }}</span> {{ glName(t.glCode) }} — {{ display(t.accountNo) }} ({{
|
|
t.accountName
|
|
}})
|
|
} @else {
|
|
<span class="cctr-contra">{{ contraLabel(t) }}</span>
|
|
}
|
|
</td>
|
|
<td class="num col-out">₹{{ legAmount(t) | number: '1.2-2' }}</td>
|
|
<td class="num"></td>
|
|
<td rowspan="2">
|
|
<span class="cctr-balanced-chip">✓ Balanced</span>
|
|
</td>
|
|
</tr>
|
|
<tr class="cctr-journal-row cctr-journal-row--second">
|
|
<td></td>
|
|
<td></td>
|
|
<td><span class="cctr-drcr cctr-drcr--cr">Cr</span></td>
|
|
<td>
|
|
@if (t.credit > 0) {
|
|
<span class="pg-chip">{{ t.glCode }}</span> {{ glName(t.glCode) }} — {{ display(t.accountNo) }} ({{
|
|
t.accountName
|
|
}})
|
|
} @else {
|
|
<span class="cctr-contra">{{ contraLabel(t) }}</span>
|
|
}
|
|
</td>
|
|
<td class="num"></td>
|
|
<td class="num col-in">₹{{ legAmount(t) | number: '1.2-2' }}</td>
|
|
</tr>
|
|
} @empty {
|
|
<tr>
|
|
<td colspan="7" class="pg-empty">No transactions for this filter.</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
<tfoot>
|
|
<tr class="cctr-total-row">
|
|
<td colspan="4">Total ({{ filteredTxns.length }} vouchers)</td>
|
|
<td class="num">
|
|
₹{{ txnTotal(filteredTxns, 'debit') + txnTotal(filteredTxns, 'credit') | number: '1.2-2' }}
|
|
</td>
|
|
<td class="num">
|
|
₹{{ txnTotal(filteredTxns, 'debit') + txnTotal(filteredTxns, 'credit') | number: '1.2-2' }}
|
|
</td>
|
|
<td></td>
|
|
</tr>
|
|
</tfoot>
|
|
</table>
|
|
</div>
|
|
}
|
|
</div>
|