fix(cashier): My Vouchers filters, Fund Transfer GL support, and disbursement-list rename
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

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.
This commit is contained in:
2026-09-10 12:40:32 +05:30
parent 03bc2ff139
commit f0c06988c0
11 changed files with 133 additions and 31 deletions
+43 -1
View File
@@ -82,7 +82,11 @@ export class MyWorkComponent implements OnInit {
period: 'DAY' | 'MONTH' = 'DAY';
anchor = this.todayIso();
/** Narrow to one side, or to the part the user played. Both applied in the browser. */
/**
* Narrow to one side, or to the part the user played. Both applied in the browser, and only to
* the table below — the five summary tiles are pinned to Entered work regardless (see
* enteredRows), so this can default to showing everything without muddying them.
*/
sideFilter: '' | VoucherSide = '';
roleFilter: '' | MyRole = '';
@@ -174,6 +178,44 @@ export class MyWorkComponent implements OnInit {
return this.rows.reduce((sum, r) => sum + Number(r.amount ?? 0), 0);
}
/**
* What this person themselves put through today — never narrowed by the Side or My part
* filters, which exist only to browse the table below.
*
* The five summary tiles are pinned to this set on purpose. They answer one question, "what did
* I personally do today", and that answer cannot depend on which slice of the list a person
* happens to have the table filtered to at the moment — a Received figure that changed whenever
* someone picked "Approved" to go look at what they'd passed would not be their own total any
* more, it would be whatever the table was showing.
*/
get enteredRows(): MyWorkRow[] {
const all = this.report?.vouchers ?? [];
return all.filter((r) => r.myRole === 'RAISED' || r.myRole === 'RAISED_AND_VERIFIED');
}
get receivedTotal(): number {
return this.enteredRows.filter((r) => r.side === 'CR').reduce((sum, r) => sum + Number(r.amount ?? 0), 0);
}
get paymentTotal(): number {
return this.enteredRows.filter((r) => r.side === 'DR').reduce((sum, r) => sum + Number(r.amount ?? 0), 0);
}
get journalTotal(): number {
return this.enteredRows
.filter((r) => r.side !== 'CR' && r.side !== 'DR')
.reduce((sum, r) => sum + Number(r.amount ?? 0), 0);
}
get raisedCount(): number {
return this.enteredRows.length;
}
get verifiedCount(): number {
const all = this.report?.vouchers ?? [];
return all.filter((r) => r.myRole === 'VERIFIED' || r.myRole === 'RAISED_AND_VERIFIED').length;
}
sideLabel(side: VoucherSide | null): string {
if (side === 'CR') {
return 'Received';