- submitBankTransfer() now calls submit() with requestType='BANK_TRANSFER' instead of the immediate-execution /banktransfer endpoint - Confirm dialog updated: 'Submit for Approval' instead of 'Execute Transfer' - disbursement-review: isBankTransferMode getter, separate DR/CR entry tables, 'Approve Bank Transfer' button label, correct isCollectionMode guard - Disbursement Requests checker inbox: Type badge (Bank Transfer/Collection/ Disbursement) column, GL column shows 'Intra-bank transfer' for BT requests - Checker inbox tab renamed to 'Disbursement & Transfers' Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
188 lines
6.2 KiB
HTML
188 lines
6.2 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="cv-tab-content wri-tab">
|
|
<!-- ── TITLE BAR ── -->
|
|
<div class="wri-action-bar">
|
|
<div class="wri-action-bar__left">
|
|
<mat-icon class="wri-action-bar__icon">swap_horiz</mat-icon>
|
|
<div>
|
|
<div class="wri-action-bar__title">Disbursement & Transfer Requests</div>
|
|
<div class="wri-action-bar__sub">
|
|
Review, approve or reject clerk disbursement, collection, and bank transfer requests.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- ── FILTER BAR ── -->
|
|
<div class="wri-filter-bar">
|
|
<select class="wri-filter-select" [(ngModel)]="filterStatus" (change)="onFilterChange()">
|
|
@for (opt of statusOptions; track opt.value) {
|
|
<option [value]="opt.value">{{ opt.label }}</option>
|
|
}
|
|
</select>
|
|
|
|
<span class="wri-fb-sep"></span>
|
|
|
|
<div class="wri-presets">
|
|
@for (p of datePresets; track p.key) {
|
|
<button
|
|
type="button"
|
|
class="wri-preset-chip"
|
|
[class.wri-preset-chip--active]="activePreset === p.key"
|
|
(click)="applyPreset(p.key)"
|
|
>
|
|
{{ p.label }}
|
|
</button>
|
|
}
|
|
</div>
|
|
|
|
<span class="wri-fb-sep"></span>
|
|
|
|
<div class="wri-date-range">
|
|
<div class="wri-date-box">
|
|
<span class="wri-date-box__lbl">From</span>
|
|
<input
|
|
class="wri-date-box__input"
|
|
[matDatepicker]="fromPicker"
|
|
[(ngModel)]="fromDate"
|
|
[max]="maxDate"
|
|
(dateChange)="onFromDateChange()"
|
|
readonly
|
|
/>
|
|
<button type="button" class="wri-date-box__btn" (click)="fromPicker.open()">
|
|
<mat-icon>event</mat-icon>
|
|
</button>
|
|
<mat-datepicker #fromPicker></mat-datepicker>
|
|
</div>
|
|
<span class="wri-date-range__sep">—</span>
|
|
<div class="wri-date-box">
|
|
<span class="wri-date-box__lbl">To</span>
|
|
<input
|
|
class="wri-date-box__input"
|
|
[matDatepicker]="toPicker"
|
|
[(ngModel)]="toDate"
|
|
[min]="fromDate"
|
|
[max]="maxDate"
|
|
(dateChange)="onToDateChange()"
|
|
readonly
|
|
/>
|
|
<button type="button" class="wri-date-box__btn" (click)="toPicker.open()">
|
|
<mat-icon>event</mat-icon>
|
|
</button>
|
|
<mat-datepicker #toPicker></mat-datepicker>
|
|
</div>
|
|
</div>
|
|
|
|
<button type="button" class="wri-btn wri-btn--refresh" (click)="load()" [disabled]="loading">
|
|
<mat-icon>refresh</mat-icon>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- ── TABLE ── -->
|
|
@if (loading) {
|
|
<div class="empty-state">
|
|
<p class="empty-title">Loading…</p>
|
|
</div>
|
|
} @else if (loaded && requests.length === 0) {
|
|
<div class="empty-state">
|
|
<i class="fas fa-inbox empty-icon"></i>
|
|
<p class="empty-title">No disbursement requests</p>
|
|
<p class="empty-text">
|
|
@if (filterStatus === 'PENDING') {
|
|
There are no pending disbursement requests waiting for review.
|
|
} @else {
|
|
No {{ filterStatus | lowercase }} disbursement requests found.
|
|
}
|
|
</p>
|
|
</div>
|
|
} @else {
|
|
<div class="wri-table-wrap">
|
|
<table class="wri-table">
|
|
<thead>
|
|
<tr>
|
|
<th class="wri-th-id">Voucher No</th>
|
|
<th>Type</th>
|
|
<th>GL Account / Details</th>
|
|
<th class="num">Amount</th>
|
|
<th>Entries</th>
|
|
<th>Clerk</th>
|
|
<th>Reviewed By</th>
|
|
<th>Submitted At</th>
|
|
<th>Status</th>
|
|
<th class="wri-th-action">Action</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (r of requests; track r.id) {
|
|
<tr class="wri-row" (click)="review(r)">
|
|
<td class="cell-mono wri-voucher">{{ r.voucher_no || '—' }}</td>
|
|
<td>
|
|
<span
|
|
class="wri-credit-badge"
|
|
[style.background]="
|
|
r.request_type === 'BANK_TRANSFER'
|
|
? '#e3f2fd'
|
|
: r.request_type === 'COLLECTION'
|
|
? '#fce4ec'
|
|
: '#e8f5e9'
|
|
"
|
|
>
|
|
{{
|
|
r.request_type === 'BANK_TRANSFER'
|
|
? 'Bank Transfer'
|
|
: r.request_type === 'COLLECTION'
|
|
? 'Collection'
|
|
: 'Disbursement'
|
|
}}
|
|
</span>
|
|
</td>
|
|
<td>
|
|
@if (r.request_type === 'BANK_TRANSFER') {
|
|
<span class="wri-gl-name">Intra-bank transfer</span>
|
|
} @else {
|
|
<span class="cell-mono">{{ r.gl_account_no }}</span>
|
|
<span class="wri-gl-name">{{ r.gl_account_name }}</span>
|
|
}
|
|
</td>
|
|
<td class="num wri-amount">₹{{ r.dr_amount | number: '1.2-2' }}</td>
|
|
<td class="wri-credit-count">
|
|
<span class="wri-credit-badge">{{ creditCount(r) }} account{{ creditCount(r) !== 1 ? 's' : '' }}</span>
|
|
</td>
|
|
<td>{{ r.clerk_name }}</td>
|
|
<td>{{ r.manager_name || r.manager_username || '—' }}</td>
|
|
<td class="wri-dt">{{ formatDateTime(r.submitted_at) }}</td>
|
|
<td>
|
|
<span class="wri-status" [ngClass]="statusClass(r.status)">
|
|
{{ statusLabel(r.status) }}
|
|
</span>
|
|
</td>
|
|
<td class="wri-action-cell" (click)="$event.stopPropagation()">
|
|
<button type="button" class="wri-btn wri-btn--review" (click)="review(r)">
|
|
<mat-icon>rate_review</mat-icon>
|
|
Review
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<mat-paginator
|
|
[length]="totalRecords"
|
|
[pageSize]="pageSize"
|
|
[pageSizeOptions]="pageSizeOptions"
|
|
[pageIndex]="pageIndex"
|
|
showFirstLastButtons
|
|
(page)="onPageChange($event)"
|
|
></mat-paginator>
|
|
}
|
|
</div>
|