Files
cbsnexora/src/app/cashier/closing-cash-report/closing-cash-report.component.html
T
niteshandClaude Sonnet 5 44b23ef110
build-run / Run Lint, Build and Deploy (push) Canceled after 0s
Publish Image in Docker Hub / build (push) Canceled after 0s
Playwright E2E Tests / Run Playwright Tests (push) Canceled after 0s
Tests / testRigor (push) Canceled after 0s
fix(shares): mandatory GL+voucher entry for advance collection, split entry-fee verification from settlement
- 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>
2026-08-30 20:05:11 +05:30

382 lines
15 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!--
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>