my-work.component (My Vouchers): - The five summary tiles (Received/Payments/Journal/Entered/Approved) were bound directly to the server's day-total fields, so they stayed fixed at the combined "entered + approved" figure no matter what the Side/My part dropdowns were set to. They're now pinned to this user's own entered rows only (enteredRows), independent of both filters, so "how much did I personally put through today" reads correctly regardless of what the table below happens to be filtered to. The table and its dropdowns are unchanged and still default to showing everything. transaction-entry.component (Fund Transfer): - onSave()'s plain bank-transfer branch (SD/CA/CB only) was catching every 'Fund Transfer' row before the GL-aware Disbursement/Collection branch below it could see them, so a Fund Transfer against a GL account was always rejected with "Invalid Account Type" even though that branch already supports it under the same label. Fund Transfer rows that include a GL leg now skip the plain-transfer branch and fall through correctly. my-disbursement-requests.component (Disbursements & Transfer list): - getCreditEntries() only read the stored credit_entries JSON, which holds the full picture for Collection (its GL leg is one of the entries) but not for Disbursement/Fund Transfer, whose GL is the request's own top-level source (gl_account_no/dr_amount) and was never in that array. The DR/CR breakdown for those two types showed only the credit side, looking like half the entry was missing. The GL leg is now synthesised back in as the first row for those two types, matching what actually posted. - Renamed the clerk's "My Disbursements" / "My Disbursement Requests" screen to "Disbursements & Transfer" throughout (nav tab, dropdown menu, route title/breadcrumb, cashier counter link, page header) — the register covers Disbursement, Collection, Fund Transfer and Bank Transfer requests, and the old name read as disbursement-only. "My Requests" (Withdrawal Slip requests, a separate register) is renamed to "Withdrawal Request" for the same reason: neither name said what was actually inside.
219 lines
7.9 KiB
HTML
219 lines
7.9 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="mdr-page">
|
|
<!-- ── HEADER ── -->
|
|
<div class="mdr-header">
|
|
<div class="mdr-header__left">
|
|
<mat-icon class="mdr-header__icon">swap_horiz</mat-icon>
|
|
<div>
|
|
<div class="mdr-header__title">Disbursements & Transfer</div>
|
|
<div class="mdr-header__sub">
|
|
Disbursement, Collection, Fund Transfer and Bank Transfer requests you submitted.
|
|
</div>
|
|
</div>
|
|
</div>
|
|
<button type="button" class="mdr-btn mdr-btn--new" (click)="newDisbursement()">
|
|
<mat-icon>add</mat-icon>
|
|
New Request
|
|
</button>
|
|
</div>
|
|
|
|
<!-- ── FILTER BAR ── -->
|
|
<div class="mdr-filter-bar">
|
|
<select class="mdr-filter-select" [(ngModel)]="filterStatus" (change)="onFilterChange()">
|
|
@for (opt of statusOptions; track opt.value) {
|
|
<option [value]="opt.value">{{ opt.label }}</option>
|
|
}
|
|
</select>
|
|
|
|
<span class="mdr-fb-sep"></span>
|
|
|
|
<div class="mdr-presets">
|
|
@for (p of datePresets; track p.key) {
|
|
<button
|
|
type="button"
|
|
class="mdr-preset-chip"
|
|
[class.mdr-preset-chip--active]="activePreset === p.key"
|
|
(click)="applyPreset(p.key)"
|
|
>
|
|
{{ p.label }}
|
|
</button>
|
|
}
|
|
</div>
|
|
|
|
<span class="mdr-fb-sep"></span>
|
|
|
|
<div class="mdr-date-range">
|
|
<div class="mdr-date-box">
|
|
<span class="mdr-date-box__lbl">From</span>
|
|
<input
|
|
class="mdr-date-box__input"
|
|
[matDatepicker]="fromPicker"
|
|
[(ngModel)]="fromDate"
|
|
[max]="maxDate"
|
|
(dateChange)="onFromDateChange()"
|
|
readonly
|
|
/>
|
|
<button type="button" class="mdr-date-box__btn" (click)="fromPicker.open()">
|
|
<mat-icon>event</mat-icon>
|
|
</button>
|
|
<mat-datepicker #fromPicker></mat-datepicker>
|
|
</div>
|
|
<span class="mdr-date-range__sep">—</span>
|
|
<div class="mdr-date-box">
|
|
<span class="mdr-date-box__lbl">To</span>
|
|
<input
|
|
class="mdr-date-box__input"
|
|
[matDatepicker]="toPicker"
|
|
[(ngModel)]="toDate"
|
|
[min]="fromDate"
|
|
[max]="maxDate"
|
|
(dateChange)="onToDateChange()"
|
|
readonly
|
|
/>
|
|
<button type="button" class="mdr-date-box__btn" (click)="toPicker.open()">
|
|
<mat-icon>event</mat-icon>
|
|
</button>
|
|
<mat-datepicker #toPicker></mat-datepicker>
|
|
</div>
|
|
</div>
|
|
|
|
<button type="button" class="mdr-btn mdr-btn--refresh" (click)="load()" [disabled]="loading">
|
|
<mat-icon>refresh</mat-icon>
|
|
</button>
|
|
</div>
|
|
|
|
<!-- ── TABLE ── -->
|
|
@if (loading) {
|
|
<div class="mdr-empty">
|
|
<p class="mdr-empty__title">Loading…</p>
|
|
</div>
|
|
} @else if (loaded && requests.length === 0) {
|
|
<div class="mdr-empty">
|
|
<i class="fas fa-inbox mdr-empty__icon"></i>
|
|
<p class="mdr-empty__title">No disbursement requests found</p>
|
|
<p class="mdr-empty__text">You have not submitted any disbursement requests yet.</p>
|
|
<button type="button" class="mdr-btn mdr-btn--new" style="margin-top: 12px" (click)="newDisbursement()">
|
|
<mat-icon>add</mat-icon>
|
|
New Request
|
|
</button>
|
|
</div>
|
|
} @else {
|
|
<div class="mdr-table-wrap">
|
|
<table class="mdr-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Voucher No</th>
|
|
<th>GL Account</th>
|
|
<th class="num">DR Amount</th>
|
|
<th>Credit Entries</th>
|
|
<th>Payment Mode</th>
|
|
<th>Reviewed By</th>
|
|
<th>Submitted At</th>
|
|
<th>Status</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (r of requests; track r.id) {
|
|
<tr class="mdr-row">
|
|
<td class="cell-mono mdr-voucher">{{ r.voucher_no || '—' }}</td>
|
|
<td>
|
|
<span class="cell-mono">{{ r.gl_account_no }}</span>
|
|
<span class="mdr-gl-name">{{ r.gl_account_name }}</span>
|
|
</td>
|
|
<td class="num mdr-amount">₹{{ r.dr_amount | number: '1.2-2' }}</td>
|
|
<td>
|
|
<button type="button" class="mdr-credit-badge mdr-credit-badge--btn" (click)="toggleExpand(r.id)">
|
|
{{ creditCount(r) }} account{{ creditCount(r) !== 1 ? 's' : '' }}
|
|
<mat-icon class="mdr-credit-chevron" [class.mdr-credit-chevron--open]="expandedIds.has(r.id)">
|
|
expand_more
|
|
</mat-icon>
|
|
</button>
|
|
</td>
|
|
<td>{{ r.payment_type_name || 'Transfer' }}</td>
|
|
<td>{{ r.manager_name || r.manager_username || '—' }}</td>
|
|
<td class="mdr-dt">{{ formatDateTime(r.submitted_at) }}</td>
|
|
<td>
|
|
<span class="mdr-status" [ngClass]="statusClass(r.status)">{{ statusLabel(r.status) }}</span>
|
|
</td>
|
|
</tr>
|
|
@if (expandedIds.has(r.id)) {
|
|
<tr class="mdr-expand-row">
|
|
<td colspan="8" class="mdr-expand-cell">
|
|
<div class="mdr-credit-preview">
|
|
<table class="mdr-credit-table">
|
|
<thead>
|
|
<tr>
|
|
<th>DR/CR</th>
|
|
<th>Account No</th>
|
|
<th>Account Name</th>
|
|
<th>Type</th>
|
|
<th class="num">Amount (₹)</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
@for (ce of getCreditEntries(r); track ce.accountNo) {
|
|
<tr>
|
|
<td>
|
|
<span
|
|
class="mdr-actype"
|
|
[style.background]="ce.dbCr === 'Dr' ? '#fee2e2' : '#dcfce7'"
|
|
[style.color]="ce.dbCr === 'Dr' ? '#991b1b' : '#166534'"
|
|
>
|
|
{{ ce.dbCr || 'CR' }}
|
|
</span>
|
|
</td>
|
|
<td class="cell-mono">{{ ce.accountNo || '—' }}</td>
|
|
<td>{{ ce.accountName || '—' }}</td>
|
|
<td>
|
|
<span class="mdr-actype">{{
|
|
ce.accountType ? accountTypeLabel(ce.accountType) : '—'
|
|
}}</span>
|
|
</td>
|
|
<td class="num mdr-ce-amount">{{ ce.amount | number: '1.2-2' }}</td>
|
|
</tr>
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
}
|
|
@if (r.status === 'REJECTED' && r.rejection_reason) {
|
|
<tr class="mdr-reason-row">
|
|
<td colspan="8" class="mdr-reason-cell">
|
|
<mat-icon class="mdr-reason-icon">info</mat-icon>
|
|
{{ r.rejection_reason }}
|
|
</td>
|
|
</tr>
|
|
}
|
|
@if (r.status === 'FAILED' && r.error_message) {
|
|
<tr class="mdr-reason-row mdr-reason-row--failed">
|
|
<td colspan="8" class="mdr-reason-cell mdr-reason-cell--failed">
|
|
<mat-icon class="mdr-reason-icon">error_outline</mat-icon>
|
|
Processing failed & transactions reversed: {{ r.error_message }}
|
|
</td>
|
|
</tr>
|
|
}
|
|
}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<mat-paginator
|
|
[length]="totalRecords"
|
|
[pageSize]="pageSize"
|
|
[pageSizeOptions]="pageSizeOptions"
|
|
[pageIndex]="pageIndex"
|
|
showFirstLastButtons
|
|
(page)="onPageChange($event)"
|
|
></mat-paginator>
|
|
}
|
|
</div>
|