- Apply Collection dialog: replace product-config auto-resolved GL account with a required GL + voucher search (mirrored for Share and Entry Fee receipts). The entry-fee receipt is tracked separately from the share receipts and sent as its own field so its amount is never swept into the Sundry-side total or double-posted — it only verifies the fee was paid, since that money already sits wherever the cashier deposited it. - Shows the account's required total (share value + entry fee) and live coverage up front, instead of only after a failed apply. - Apply Additional Shares: same mandatory GL + voucher pattern for its by-voucher lookup, plus a GL account picker fed by the new /shareadvancecollection/glaccounts endpoint. - shares-account-charges-step: fixed a race where the currency-control subscription (meant only for the edit-an-existing-application flow) wiped out product charges that ngOnChanges had just seeded from the same product-selection event, leaving new accounts with no charges. - shares-account-view: hide "Share Certificate" until collection_applied is true, so a certificate can't be printed for shares nobody has actually paid for yet. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
382 lines
15 KiB
HTML
382 lines
15 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">CASHIER · REPORT</div>
|
||
<h1 class="pg-title">Closing Cash Report</h1>
|
||
<p class="pg-sub">Denomination-wise deposit, withdrawal and net cash position for the selected day.</p>
|
||
</div>
|
||
<div class="pg-toolbar">
|
||
<label class="pg-field">
|
||
<span>Date</span>
|
||
<input type="date" [value]="date" (change)="date = $any($event.target).value" />
|
||
</label>
|
||
<button type="button" class="pg-btn pg-btn--primary" (click)="load()" [disabled]="loading">
|
||
<mat-icon>search</mat-icon> Load
|
||
</button>
|
||
<button type="button" class="pg-btn" [class.pg-btn--active]="showGl" (click)="toggleGl()">
|
||
<mat-icon>account_balance</mat-icon> GL View
|
||
</button>
|
||
</div>
|
||
</header>
|
||
|
||
@if (!showGl && rows.length > 0) {
|
||
<!-- Summary totals bar -->
|
||
<div class="closing-summary">
|
||
<div class="closing-summary__item closing-summary__item--in">
|
||
<span class="closing-summary__label">Total Deposits (IN)</span>
|
||
<span class="closing-summary__value">₹{{ depositTotal | number: '1.2-2' }}</span>
|
||
</div>
|
||
<div class="closing-summary__sep">−</div>
|
||
<div class="closing-summary__item closing-summary__item--out">
|
||
<span class="closing-summary__label">Total Withdrawals (OUT)</span>
|
||
<span class="closing-summary__value">₹{{ withdrawalTotal | number: '1.2-2' }}</span>
|
||
</div>
|
||
<div class="closing-summary__sep">=</div>
|
||
<div
|
||
class="closing-summary__item"
|
||
[class.closing-summary__item--net-pos]="netTotal >= 0"
|
||
[class.closing-summary__item--net-neg]="netTotal < 0"
|
||
>
|
||
<span class="closing-summary__label">Net Closing Cash</span>
|
||
<span class="closing-summary__value">₹{{ netTotal | number: '1.2-2' }}</span>
|
||
</div>
|
||
</div>
|
||
}
|
||
|
||
@if (!showGl) {
|
||
<div class="pg-card">
|
||
@if (noteRows.length > 0) {
|
||
<div class="pos-section-label">Notes</div>
|
||
<table class="pg-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Denomination</th>
|
||
<th class="num col-in">Deposit Pcs</th>
|
||
<th class="num col-in">Deposit Amt</th>
|
||
<th class="num col-out">Withdrawal Pcs</th>
|
||
<th class="num col-out">Withdrawal Amt</th>
|
||
<th class="num col-net">Net Pcs</th>
|
||
<th class="num col-net">Net Amount</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
@for (r of noteRows; track r.denominationId) {
|
||
<tr>
|
||
<td>
|
||
<span class="pg-chip">₹{{ r.denominationValue }}</span>
|
||
</td>
|
||
<td class="num col-in">{{ r.depositCount }}</td>
|
||
<td class="num col-in">₹{{ r.depositAmount | number: '1.2-2' }}</td>
|
||
<td class="num col-out">{{ r.withdrawalCount }}</td>
|
||
<td class="num col-out">₹{{ r.withdrawalAmount | number: '1.2-2' }}</td>
|
||
<td
|
||
class="num col-net"
|
||
[style.color]="r.netCount > 0 ? '#16a34a' : r.netCount < 0 ? '#dc2626' : '#94a3b8'"
|
||
>
|
||
{{ r.netCount > 0 ? '+' : '' }}{{ r.netCount }}
|
||
</td>
|
||
<td
|
||
class="num col-net"
|
||
[style.color]="r.netCount > 0 ? '#16a34a' : r.netCount < 0 ? '#dc2626' : '#94a3b8'"
|
||
>
|
||
{{ r.netCount >= 0 ? '' : '−' }}₹{{
|
||
(r.netAmount < 0 ? -r.netAmount : r.netAmount) | number: '1.2-2'
|
||
}}
|
||
</td>
|
||
</tr>
|
||
}
|
||
</tbody>
|
||
</table>
|
||
}
|
||
|
||
@if (coinRows.length > 0) {
|
||
<div class="pos-section-label pos-section-label--coin">Coins</div>
|
||
<table class="pg-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Denomination</th>
|
||
<th class="num col-in">Deposit Pcs</th>
|
||
<th class="num col-in">Deposit Amt</th>
|
||
<th class="num col-out">Withdrawal Pcs</th>
|
||
<th class="num col-out">Withdrawal Amt</th>
|
||
<th class="num col-net">Net Pcs</th>
|
||
<th class="num col-net">Net Amount</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
@for (r of coinRows; track r.denominationId) {
|
||
<tr>
|
||
<td>
|
||
<span class="pg-chip pg-chip--coin">₹{{ r.denominationValue }}</span>
|
||
</td>
|
||
<td class="num col-in">{{ r.depositCount }}</td>
|
||
<td class="num col-in">₹{{ r.depositAmount | number: '1.2-2' }}</td>
|
||
<td class="num col-out">{{ r.withdrawalCount }}</td>
|
||
<td class="num col-out">₹{{ r.withdrawalAmount | number: '1.2-2' }}</td>
|
||
<td
|
||
class="num col-net"
|
||
[style.color]="r.netCount > 0 ? '#16a34a' : r.netCount < 0 ? '#dc2626' : '#94a3b8'"
|
||
>
|
||
{{ r.netCount > 0 ? '+' : '' }}{{ r.netCount }}
|
||
</td>
|
||
<td
|
||
class="num col-net"
|
||
[style.color]="r.netCount > 0 ? '#16a34a' : r.netCount < 0 ? '#dc2626' : '#94a3b8'"
|
||
>
|
||
{{ r.netCount >= 0 ? '' : '−' }}₹{{
|
||
(r.netAmount < 0 ? -r.netAmount : r.netAmount) | number: '1.2-2'
|
||
}}
|
||
</td>
|
||
</tr>
|
||
}
|
||
</tbody>
|
||
</table>
|
||
}
|
||
|
||
@if (loaded && rows.length === 0 && exchangeRows.length === 0) {
|
||
<div class="pg-empty">No cash denomination data for this date.</div>
|
||
}
|
||
</div>
|
||
}
|
||
<!-- end !showGl -->
|
||
|
||
<!-- GL View Panel -->
|
||
@if (showGl) {
|
||
<div class="gl-card">
|
||
<!-- Card Header -->
|
||
<div class="gl-card__header">
|
||
<div class="gl-card__header-left">
|
||
<div class="gl-card__icon">
|
||
<mat-icon>account_balance</mat-icon>
|
||
</div>
|
||
<div>
|
||
<div class="gl-card__title">GL Entries</div>
|
||
<div class="gl-card__sub">Cashier transaction ledger for {{ date }}</div>
|
||
</div>
|
||
</div>
|
||
<div class="gl-card__totals">
|
||
<div class="gl-card__total gl-card__total--dr">
|
||
<span class="gl-card__total-label">Total DR</span>
|
||
<span class="gl-card__total-value">₹{{ glTotalDr | number: '1.2-2' }}</span>
|
||
</div>
|
||
<div class="gl-card__total-sep">|</div>
|
||
<div class="gl-card__total gl-card__total--cr">
|
||
<span class="gl-card__total-label">Total CR</span>
|
||
<span class="gl-card__total-value">₹{{ glTotalCr | number: '1.2-2' }}</span>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- Filters Bar -->
|
||
<div class="gl-card__filters">
|
||
<label class="pg-field">
|
||
<span>Teller Head</span>
|
||
<select class="pg-select" [(ngModel)]="selectedTellerId" (change)="onTellerChange()">
|
||
<option [ngValue]="null">All Tellers</option>
|
||
@for (t of tellers; track t.id) {
|
||
<option [ngValue]="t.id">{{ t.name }}</option>
|
||
}
|
||
</select>
|
||
</label>
|
||
@if (selectedTellerId) {
|
||
<label class="pg-field">
|
||
<span>Cashier</span>
|
||
<select class="pg-select" [(ngModel)]="selectedCashierId" (change)="onCashierChange()">
|
||
<option [ngValue]="null">All Cashiers</option>
|
||
@for (c of cashiers; track c.id) {
|
||
<option [ngValue]="c.id">{{ c.staffName }}</option>
|
||
}
|
||
</select>
|
||
</label>
|
||
}
|
||
<button type="button" class="pg-btn pg-btn--primary" (click)="loadGl()" [disabled]="glLoading">
|
||
<mat-icon>refresh</mat-icon> Refresh
|
||
</button>
|
||
</div>
|
||
|
||
<!-- Table -->
|
||
@if (glLoading) {
|
||
<div class="pg-empty">Loading...</div>
|
||
} @else if (glRows.length === 0 && glLoaded) {
|
||
<div class="pg-empty">No entries found for this date and filter.</div>
|
||
} @else if (glRows.length > 0) {
|
||
<table class="pg-table gl-table">
|
||
<thead>
|
||
<tr>
|
||
<th class="gl-th--voucher">Voucher No</th>
|
||
<th class="gl-th--date">Date</th>
|
||
<th>A/C No</th>
|
||
<th>A/C Name</th>
|
||
<th class="gl-th--pt">Payment Type</th>
|
||
<th class="gl-th--teller">Teller</th>
|
||
<th class="num gl-th--dr">DR (₹)</th>
|
||
<th class="num gl-th--cr">CR (₹)</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
@for (r of glRows; track $index) {
|
||
<tr [class.gl-row--dr]="r.dr > 0" [class.gl-row--cr]="r.cr > 0">
|
||
<td class="gl-voucher">
|
||
@if (r.txnSource === 'GL') {
|
||
<span class="gl-badge">GL</span>
|
||
}
|
||
{{ r.voucherNo }}
|
||
</td>
|
||
<td class="gl-date">
|
||
<div>{{ r.txnDate }}</div>
|
||
@if (r.txnTime) {
|
||
<div class="gl-time">{{ r.txnTime }}</div>
|
||
}
|
||
</td>
|
||
<td class="gl-acno">{{ r.acNo }}</td>
|
||
<td class="gl-acname">{{ r.acName }}</td>
|
||
<td class="gl-pt">
|
||
@if (r.paymentType) {
|
||
<span class="gl-pt-badge">{{ r.paymentType }}</span>
|
||
} @else {
|
||
<span class="gl-pt-none">—</span>
|
||
}
|
||
</td>
|
||
<td class="gl-teller">{{ r.tellerName || '—' }}</td>
|
||
<td class="num gl-amt--dr">
|
||
@if (r.dr > 0) {
|
||
₹{{ r.dr | number: '1.2-2' }}
|
||
}
|
||
</td>
|
||
<td class="num gl-amt--cr">
|
||
@if (r.cr > 0) {
|
||
₹{{ r.cr | number: '1.2-2' }}
|
||
}
|
||
</td>
|
||
</tr>
|
||
}
|
||
</tbody>
|
||
<tfoot>
|
||
<tr class="gl-foot">
|
||
<td colspan="6" class="gl-foot__label">Total (All Pages)</td>
|
||
<td class="num gl-amt--dr gl-foot__val">₹{{ glTotalDr | number: '1.2-2' }}</td>
|
||
<td class="num gl-amt--cr gl-foot__val">₹{{ glTotalCr | number: '1.2-2' }}</td>
|
||
</tr>
|
||
</tfoot>
|
||
</table>
|
||
<mat-paginator
|
||
[length]="glTotal"
|
||
[pageSize]="glPageSize"
|
||
[pageSizeOptions]="glPageSizeOptions"
|
||
[pageIndex]="glOffset / glPageSize"
|
||
showFirstLastButtons
|
||
(page)="onGlPageChange($event)"
|
||
></mat-paginator>
|
||
}
|
||
</div>
|
||
}
|
||
|
||
@if (!showGl && exchangeRows.length > 0) {
|
||
<div class="pg-card">
|
||
<div class="closing-exchange-head">
|
||
<mat-icon>swap_horiz</mat-icon>
|
||
<div>
|
||
<div class="closing-exchange-title">Cash Exchanges</div>
|
||
<div class="closing-exchange-sub">Denomination swaps recorded on this date (net cash impact: ₹0.00)</div>
|
||
</div>
|
||
</div>
|
||
|
||
@if (exchangeNoteRows.length > 0) {
|
||
<div class="pos-section-label">Notes</div>
|
||
<table class="pg-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Denomination</th>
|
||
<th class="num col-in">Received Pcs</th>
|
||
<th class="num col-in">Received Amt</th>
|
||
<th class="num col-out">Given Pcs</th>
|
||
<th class="num col-out">Given Amt</th>
|
||
<th class="num col-net">Net Pcs</th>
|
||
<th class="num col-net">Net Amount</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
@for (r of exchangeNoteRows; track r.denominationId) {
|
||
<tr>
|
||
<td>
|
||
<span class="pg-chip">₹{{ r.denominationValue }}</span>
|
||
</td>
|
||
<td class="num col-in">{{ r.receivedCount }}</td>
|
||
<td class="num col-in">₹{{ r.receivedAmount | number: '1.2-2' }}</td>
|
||
<td class="num col-out">{{ r.givenCount }}</td>
|
||
<td class="num col-out">₹{{ r.givenAmount | number: '1.2-2' }}</td>
|
||
<td
|
||
class="num col-net"
|
||
[style.color]="r.netCount > 0 ? '#16a34a' : r.netCount < 0 ? '#dc2626' : '#94a3b8'"
|
||
>
|
||
{{ r.netCount > 0 ? '+' : '' }}{{ r.netCount }}
|
||
</td>
|
||
<td
|
||
class="num col-net"
|
||
[style.color]="r.netCount > 0 ? '#16a34a' : r.netCount < 0 ? '#dc2626' : '#94a3b8'"
|
||
>
|
||
{{ r.netCount >= 0 ? '' : '−' }}₹{{
|
||
(r.netAmount < 0 ? -r.netAmount : r.netAmount) | number: '1.2-2'
|
||
}}
|
||
</td>
|
||
</tr>
|
||
}
|
||
</tbody>
|
||
</table>
|
||
}
|
||
|
||
@if (exchangeCoinRows.length > 0) {
|
||
<div class="pos-section-label pos-section-label--coin">Coins</div>
|
||
<table class="pg-table">
|
||
<thead>
|
||
<tr>
|
||
<th>Denomination</th>
|
||
<th class="num col-in">Received Pcs</th>
|
||
<th class="num col-in">Received Amt</th>
|
||
<th class="num col-out">Given Pcs</th>
|
||
<th class="num col-out">Given Amt</th>
|
||
<th class="num col-net">Net Pcs</th>
|
||
<th class="num col-net">Net Amount</th>
|
||
</tr>
|
||
</thead>
|
||
<tbody>
|
||
@for (r of exchangeCoinRows; track r.denominationId) {
|
||
<tr>
|
||
<td>
|
||
<span class="pg-chip pg-chip--coin">₹{{ r.denominationValue }}</span>
|
||
</td>
|
||
<td class="num col-in">{{ r.receivedCount }}</td>
|
||
<td class="num col-in">₹{{ r.receivedAmount | number: '1.2-2' }}</td>
|
||
<td class="num col-out">{{ r.givenCount }}</td>
|
||
<td class="num col-out">₹{{ r.givenAmount | number: '1.2-2' }}</td>
|
||
<td
|
||
class="num col-net"
|
||
[style.color]="r.netCount > 0 ? '#16a34a' : r.netCount < 0 ? '#dc2626' : '#94a3b8'"
|
||
>
|
||
{{ r.netCount > 0 ? '+' : '' }}{{ r.netCount }}
|
||
</td>
|
||
<td
|
||
class="num col-net"
|
||
[style.color]="r.netCount > 0 ? '#16a34a' : r.netCount < 0 ? '#dc2626' : '#94a3b8'"
|
||
>
|
||
{{ r.netCount >= 0 ? '' : '−' }}₹{{
|
||
(r.netAmount < 0 ? -r.netAmount : r.netAmount) | number: '1.2-2'
|
||
}}
|
||
</td>
|
||
</tr>
|
||
}
|
||
</tbody>
|
||
</table>
|
||
}
|
||
</div>
|
||
}
|
||
</div>
|