Approve, close, reject, undo-approval, withdraw-by-client, and post-interest
on a savings account all silently behaved as if nothing happened when the
backend parks the command in the Checker Inbox instead of executing it
(HTTP 200 with rollbackTransaction: true) -- misleading the maker into
thinking the action either failed or quietly succeeded. Each now shows an
explicit alert naming what was sent for approval and that the account/
application is unchanged until a checker approves it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Brings in partner's "Enforce same-user maker-checker restriction" and
related client-KYC-step / product-edit-diff-dialog work.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Premature Close dialog: adds the Closure Reason dropdown, the explicit
Waive Penalty checkbox, a tenure/date preview panel, and an "Effective
Rate for this closure" display so the maker sees exactly what rate and
penalty treatment is about to apply.
Renewal History tab: the latest term's card kept showing an ACTIVE badge
even after the account was prematurely closed, since the archived
renewal-status column only ever updates on an actual renewal rollover.
For the last card only, status now cross-checks the account's own live
status instead. "Projected Maturity" now reads "Closed At" once that
term has prematurely closed, rather than implying it's still a projection.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
otherGlMappings (the nested document behind Savings/Current/FD/RD Interest
Payable/Paid and similar named accounts) was excluded from the generic
field diff entirely, and the backend was silently dropping its value
anyway (see the paired backend fix). Now that the backend correctly
stages this field, diff it explicitly: find each reserved account name
across original.otherGlMappingsMap and proposed.otherGlMappings, resolve
the GL code to a readable name, and show a row only when it actually
moved -- same convention as every other field in this dialog, instead of
a raw JSON blob or nothing at all.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Current account passbook hardcoded "LincPay Co-operative Bank Ltd." and had
no branch identification line at all, unlike the savings passbook which
pulls the bank name and branch/IFSC/MICR details from the Institution and
Branch Profile. Wire up the same OrganizationService lookup so the current
account statement shows real bank/branch details too.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Manager withdrawal-review screen always searched the Savings account
type regardless of the request's actual account_type, so reviewing a
Current-account withdrawal failed with "Account not found". Reuse the
existing SEARCH_ACCOUNT_TYPE_TO_AC_TYP mapping (already used by the
cashier lookup path) instead of a hardcoded 'SD'.
- Point the UI tenant id at utkarshbank (was lincpay) to match the new
backend tenant.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Payment showed for both Active and Matured FDs, even though an Active FD
already has Premature Close for closing early. Now Matured-only.
That also meant a genuinely matured, past-grace FD closed via the account's
own Payment button (rather than the FD Dashboard's Renew action) silently
skipped crediting its gap-period interest -- the date-locking and
gap-interest preview/crediting were gated behind dashboard-only data, not
the account's actual matured state. Both now key off the same
renewal-preview response regardless of entry point, so Payment and Renew
are functionally identical once an FD has matured, as they should be since
they're already the same dialog component.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Was a full-page form at a dedicated route, reached by navigating away from
the account -- now a popup dialog in the same visual language as the
Payment/Renew dialog, just in this Danger Zone action's own red accent.
Also fixes a real gap in the form it replaces: the premature amount/action
options never loaded until a maker happened to touch the date picker, since
the calculation was only ever triggered on value change, never on open.
Added a breakdown panel showing exactly how the shown Maturity Amount was
reached -- Deposit Amount, Contracted Interest Rate, Pre-Closure Penalty
(when applicable), and the resulting Interest Earned -- using data the
account-view page already had, since the calculation endpoint itself only
ever returns the final number.
Removed the now-dead full-page component/route target it replaces.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The table fell back to the backend's own default order (entry_date, id
ascending) until a maker clicked a column header, so the oldest entries
sat at the top on every fresh load. Defaults the table's sort to id
descending instead.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The preview panel said interest would go to "the linked Savings account"
without saying which one. Now shows its actual account number, both as its
own row and in the highlighted "paid to" line.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Removing the forced default on this hidden, backend-mandatory field fixed
a false "changed" diff on product edit, but also broke plain product
create -- there's no saved value yet for a brand-new product, so it went
in blank and the backend rejected it as missing. Now only skips the
default when editing an existing product (which always has its own saved
value); create still defaults to 1, same as before that diff-dialog fix.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Fetches current balance, gap days since maturity, the linked savings
account's rate, and the resulting gap-interest amount and projected new
balance, and displays them above the dashboard-renewal timing text --
so staff see exactly what a late renewal is about to credit before
confirming anything. Read-only; failure to load the preview doesn't
block the renewal itself, since the existing timing text already
explains the action.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The Payment dialog (Transfer to Savings / Reinvest Full / Reinvest Principal Only / Partial
Reinvest, works whether an FD is Active or Matured) already had a complete, correct backend
implementation for every closure type -- including one this session found and fixed a real gap
in on the backend side (Reinvest Principal Only silently stranded its leftover interest). Rather
than duplicating that logic in a second, narrower dialog, the FD Dashboard's Renew action now
opens this same dialog in a `dashboardRenewal` mode: every closure type is still available, but
the Closed On Date is computed from the product's grace window instead of picked freely
(backdated to the original maturity date within grace, today once it's passed, picker hidden so
it can't be moved off that value), and submit() calls the new gap-interest pre-step endpoint
first when past grace, before the same generic `payment` command every other caller already used.
Also: full visual redesign (bigger dialog, gradient header, per-option accent colors, refined
spacing) applied to both entry points since they're the same component now; removes the native
"Close" action from a Matured FD's Account Actions menu, since what happens at maturity now
goes through the nightly job or this dialog, not a separate close command that bypassed both.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Maturity Instructions can now be left unselected when opening a SINGLE/DOUBLE/SPECIAL FD --
a new "-- Not selected (decide later via FD Dashboard) --" option, plus a clear button next to
the field, since a maker had no way to go back to blank once something was picked. An account
left this way is never touched by the nightly maturity job; what happens to it at maturity is
decided later, manually, from the FD Dashboard's Renew action (see the backend/dashboard
commits) -- an explicit choice here still auto-processes on its own exactly as before.
Also fixes a real, separate pre-existing bug found in the same step: editing an existing
account never read back its own already-saved Maturity Instructions/transfer-target choice --
the Edit screen always opened onto a blank picker even for an account that genuinely had one
set, because it was being read from the wrong template object (the blank per-product default
template refetched from the Product dropdown, not the actual account+template response that
carries the account's own saved values).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Three separate bugs in the checker's "Proposed changes" dialog, found while adding the
Renewal Grace Period field above:
- The "current" side resolved an enum field's value against the wrong payload key
(preClosurePenalInterestOnTypeId, minDepositTermTypeId, etc. are exposed on the stored
product as an object under a differently-named field, e.g. preClosurePenalInterestOnType.id)
so it always read as blank -- these fields showed as changed on every single edit, never
just the ones a maker actually touched.
- Enum/option fields resolved their label against a naive `<field>Options` key that doesn't
match Fineract's actual (inconsistent) naming, so a genuinely changed field showed its raw
numeric id instead of the option a maker picked.
- Renewal Grace Period Days and other newer fields never appeared at all, because the
maker-checker pending-edit mirror table didn't carry them (see the backend commit for that).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Frontend half of the new per-product grace-period field: number input alongside the existing
term fields, and stops forcing real default values (1 / the first period-frequency option) onto
minDepositTerm/minDepositTermTypeId, two hidden fields nobody actually edits through this form
-- left blank like their max-/in-multiples-of- siblings already correctly were, so a governed
product edit's "Proposed changes" diff no longer showed these as changed on every unrelated edit.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New screen (Deposits menu, repurposing the dead "FD Maturity Report" shell button): every
active Fixed Deposit positioned against its own maturity date (Matured / Due Soon / Upcoming /
On Track), computed client-side from maturityDate so it can never drift out of step with the
account. Reads the new lean maturity-dashboard backend endpoint.
A matured, renewable row (no maturity instruction chosen at account-opening, or an explicit
Reinvest instruction still waiting on its product's grace period) gets a Renew action wired to
the account's own Payment dialog -- see the FD account-view commit for that side of it.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
SYMPTOM
A cashier could credit an FD or RD account with cash from Transaction
Entry and the money moved in instantly, with no Manager approval -
unlike a Savings/Current deposit from the same screen, which correctly
creates a PENDING request under Approvals.
ROOT CAUSE
confirmSubmit()'s maker-checker branch for a cashier deposit only
matched row.acTyp in ('SD','CA','CB','GL'):
if (!this.isClerk && !this.reviewMode && isDeposit &&
(row.acTyp === 'SD' || row.acTyp === 'CA' || row.acTyp === 'CB' || row.acTyp === 'GL')) {
this.submitCashierDepositRequest(row, ...);
return;
}
'FD' and 'RD' are their own distinct account-type codes in this
component (see creditEntryAccountType(): 'FD' -> 'FIXED_DEPOSIT', 'RD'
-> 'RECURRING_DEPOSIT', separate from 'SD'/'CA'/'CB') and were simply
never in this list, so a deposit into either fell through every later
branch (all of which are withdrawal/disbursement-only) straight to the
generic, unguarded direct POST at the bottom of confirmSubmit().
Found by tracing why a real FD funding deposit never showed up under
Branch Ops -> Approvals: it had posted directly, no request record
ever existed for it, and it later showed up as an unexplained cash
"Excess" in the Branch Day Register close (the money was physically
counted by the cashier via denominationBreakdown in the same direct
POST, but the approved-requests-only "book" total never counted it -
see the paired backend commit for the matching approve()-side fix and
how that stale data artifact was cleaned up).
FIX
Added 'FD' and 'RD' to the account-type list in that gate, so a
cashier's FD/RD deposit now creates a PENDING
m_cashier_deposit_request via submitCashierDepositRequest() exactly
like SD/CA/CB/GL already did. buildDepositPayload() needed no changes
- it already resolves accountType via creditEntryAccountType() and
sets savingsAccountId to the FD/RD account's own id correctly; only
this one gate condition excluded them.
SCOPE
This one condition, in this one method. Every other account type's
existing deposit/withdrawal behavior on this screen is unchanged.
IF THIS BREAKS SOMETHING LATER
- A cashier FD/RD deposit posting instantly again (no PENDING request
created) -> check this gate's account-type list still includes
'FD'/'RD', and that isClerk/reviewMode aren't being set unexpectedly
for a cashier session.
- The backend rejecting or misrouting the resulting APPROVED request
-> see the paired fix in CashierDepositRequestApiResource
(cbsnexora-backend), resolveDepositAccountCategory() /
executeFixedDepositDeposit() / executeRecurringDepositDeposit().
- A "Vault + Cashiers" vs "book" Excess reappearing in Branch Day
Register close for a specific FD/RD deposit -> that combination
(physically counted denomination with no approved request) should be
impossible with this fix in place; if it recurs, this fix (or its
backend half) has regressed.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
SYMPTOM
FD Single account create screen, Rate Calculator: entering a tenure
under 30 days (e.g. 27) and clicking "Find Rate" produced a Bad
Request - "The parameter `tenureInMonths` must be greater than 0."
ROOT CAUSE
calculateRate() (fixed-deposit-account-interest-rate-chart-step.
component.ts) always converted the Days-unit tenure to months before
calling the backend calculator:
tenureInMonths = Math.floor(enteredDays / 30)
For any tenure under 30 days this floors to 0, which the backend
correctly rejects (paired backend commit: "FD Single Rate Calculator
crashed for tenures under 30 days").
FIX
- fixed-deposits.service.ts: calculateFixedDepositInterest() -
tenureInMonths is now optional, added optional tenureInDays.
- fixed-deposit-account-interest-rate-chart-step.component.ts -
calculateRate(): for a Days-unit tenure >= 30 days, unchanged
(tenureInMonths = floor(days/30)); for < 30 days, sends tenureInDays
instead and leaves tenureInMonths undefined. Also fixed the
API-failure fallback's periodic-compounding math, which divided by
tenureInMonths directly and would have produced NaN once
tenureInMonths could legitimately be undefined - it now falls back
to (enteredDays / 30) when tenureInMonths is absent.
SCOPE
Only the Rate Calculator preview inside the FD Single/Double/Special
account create screen. Does not touch how depositPeriod /
depositPeriodFrequencyId get sent on actual account submission.
IF THIS BREAKS SOMETHING LATER
- The same 400 reappearing for a short FD Single tenure -> confirm the
Find Rate network call carries tenureInDays and NOT a zero
tenureInMonths; check calculateRate()'s branch choosing between the
two.
- A wrong maturity preview number specifically when the backend API
call fails and the frontend falls back to its own formula -> check
the `effectiveMonths = tenureInMonths ?? enteredDays / 30` fallback
line in calculateRate().
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Apply Collection and Apply Additional Shares settle the same Share Collection
receipts for the same member, so they are now deliberately the same screen.
Apply Collection takes exactly two receipts and no more: one for the share value,
one for the entry fee, in two separate slots. They are different things -- the
share receipt is money moving into share capital, while the fee receipt only
proves the fee was already collected and is never posted a second time -- and
picking both out of one ticked list made that distinction invisible.
Apply Additional Shares moves from its own route to a dialog. It was a full page
a clerk had to leave the account for and come back from, to fill in a short form
with the member standing at the counter. Its old route, resolver case and action-
host branch are removed rather than left behind as dead paths.
Both screens now draw their receipts from a single pool, whether a receipt
already names the member or is a voucher paid straight into a GL account; an
unattributed one is attached at the moment it is picked, so what used to be an
Attach in one table and a tick in another is one deliberate click. The by-voucher
search and the GL-entry detail both sit behind buttons, as exceptions rather than
permanent furniture.
Dialog chrome and the receipt shape are shared (share-dialog.shared.scss,
share-receipt-option.ts) so the two cannot drift apart again.
Also fixes content being clipped at the dialog edges: the wrapper cancelled a
24px surface padding that the panel class had already zeroed, pushing every edge
outside the surface where overflow:hidden cut it off, and the height cap sat on
the scrolling body rather than the wrapper, letting the footer stack past the
bottom of the viewport.
Adds the product-wise share summary report (authorised, issued, available and
unpaid shares, distinctive range and account count per product).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The GL Account / Voucher No lookup is for the exception -- a receipt the
unattributed list and the member's own list do not already carry -- so it now
sits behind a "Search a Voucher Not Listed Below" button in both Apply
Collection and Apply Additional Shares, opening the same lookup in a popup
(matching the existing receipt-detail popup) instead of occupying screen space
whether or not anyone needs it. A successful find closes the popup and the
result appears ticked in the list behind it, same as before.
- Add the full Share Reports surface (final balance, account statement,
issued/status/nominal/share-wise/guarantor/member-interest reports, enquiry,
payment certificate, share detail, dividend statement, folio statement,
distinctive numbers, area-wise, mailing labels/letters, share transfer) as
standalone routed components, wired into the Share menu
- Wire the unattributed Share Collection receipt list into Apply Collection
and Apply Additional Shares, with an Attach action independent of
account/client
- Sync the GL Account and Voucher No fields to whichever receipt is ticked or
found, and surface the receipt's real Dr/Cr GL entries in its detail popup
- Block Apply Additional Shares until the account's original application is
settled
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds an Entry Type field to Transaction Entry's GL-crediting rows (Receipt / Collection),
fetched from the backend's GLEntryType code, so the counter can flag what a GL credit is
actually for (General / Share Collection / DD Issue) instead of leaving every GL account
picker throughout Share Advance Collection guessing from the whole chart of accounts.
Apply Share / Additional Share screens:
- GL Account picker narrowed to accounts that actually have an eligible receipt, and only
auto-selected when exactly one candidate exists -- no more defaulting to whichever account
sorts first (Cash at Vault).
- Voucher tables show Description and Collected By, and a Detail view exposes the receipt's
real Dr/Cr GL legs instead of the GL Account dropdown's current unrelated selection.
- Additional Share funds from a single voucher (radio-style selection); ticking a receipt
syncs the GL Account picker to its own actual account.
- Checker's Additional Share Request review dialog gets the same Description + real GL entry
detail, expandable per voucher, so approval is never a guess about what will post.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Share Products:
- "Share Reference (Cash Vault or Suspense)" removed from the accounting step (create, edit,
preview and the read-only view tab) -- every register now books a share transaction against the
account the money actually reached, so no product needs a placeholder asset mapping any more.
The field is now optional server-side, not required.
Cashier:
- Removed the Share Collection screen and its three service methods. It read
m_share_account.cashier_collected, a column that has never existed in this schema, and no other
screen ever called it -- it could not have produced a working entry.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Transaction Entry (clerk):
- Route a two-row Fund Transfer of Dr SHR / Cr GL to the share-withdrawal
request with settlementMode GL, so a clerk can settle a share withdrawal
into any GL account instead of the member's linked savings account.
- Offer GL as an account type for Demand Draft funding, and submit it as a
GL debit (no client or savings/current account is involved).
My Work:
- Add a voucher detail dialog so a clerk can open a raised voucher from the
request list and see its GL lines.
Closing Cash Report:
- Fix the total row so it reflects the corrected opening balance.
DD Leaflet Registry and DD Inventory:
- Redesign both pages onto the shared usr-* visual language: gradient header
badge, status filter chips with counts, card-wrapped sticky-header table,
and one primary action per row with the rest behind an overflow menu.
Filtering, pagination and every action condition are unchanged.
- Register faHandPaper, needed by the new Stop Payment menu item.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Root cause of blank/clipped print output across the app: the document root
(html/body) is globally locked to one viewport height with overflow hidden,
and Angular Material's drawer/tab-body containers each add their own
on-screen scroll clip on top of that. main.scss now frees the full chain for
print (document root, CDK drawer/sidenav containers, mat-tab-body, and the
account-view's mat-tab-nav-bar which was rendering as a stray grey scrollable
strip since it isn't covered by the mat-tab-group header rule already hidden).
Also fixed both certificate print dialogs (share-certificate-dialog,
deposit-certificate-dialog) reusing a `::ng-deep body > :not(.cdk-overlay-
container)` rule to hide the shell during their own print: under Angular's
style encapsulation this style is emitted fully unscoped into the global
stylesheet and is never removed once the component has loaded once in a
session, silently blanking every other page's print output for the rest of
the session. Dropped `::ng-deep` from that one selector so it goes back to
being properly scoped (and therefore inert, matching the other two dialogs
that never had this bug) — the app shell is already hidden for every print
via the global main.scss rules, so no dialog needs its own global override.
- Certificate PDFs, the preview dialog, and both share-certificate list views
(demo + live) now pull bank name/address/reg no/seal text from the
Institution Profile instead of a hardcoded "Nexora" identity.
- Certificate preview dialog print CSS was clipped to the dialog's on-screen
scroll viewport (maxHeight config); switched to position:fixed + unclipped
overlay ancestors so the full certificate prints, not just a border sliver.
- Global print stylesheet now also hides the app shell's real 2-row nav menu
(.main-header/.kpi-ticker, not routed through <mifosx-toolbar>) and frees
the CDK sidenav/tab-body scroll clipping, so printing any page no longer
captures the nav chrome or gets cut off to one screen's height.
Same number in both fields defeats the point of having a second contact
route, and re-running DIP on an identical number is pointless. Added a
cross-field validator on alternateMobileNo, re-checked whenever mobileNo
changes, with a matching error message and the Verify-with-DIP button
disabled while the clash exists.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The CKYC tab's document cards now open a dedicated dialog (with client-side
preview) instead of expanding inline, collecting document type, number, and
issue/expiry dates the same way client creation does. Fixes several bugs
found along the way:
- Uploading a document type that's valid for both identity and address
(Aadhaar, Passport, etc.) no longer 404s or 500s — the "no such endpoint"
and case-sensitive ClientIdentifierStatus.valueOf("Active") crashes are
both resolved.
- Edit Client's Identity-proof and Address-proof steps no longer show each
other's document when both are dual-purpose OVD types, and no longer show
stale/mismatched front-back scans after a document type change.
- Address-proof's own document preview never showed a document at all when
no m_client_kyc record existed yet.
Document number and issue/expiry dates are persisted on the identifier
(documentKey + a shared "Issue date: ..., Expiry date: ..." description
convention) and read back by both the CKYC tab and Edit Client so the same
details appear everywhere.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Transaction Entry's manual GL-entry screen was recording its denomination
breakdown against whichever GL account the teller selected, not the vault
account whose physical notes actually moved -- resolve and use the Cash
Vault GL's own code/name dynamically instead
- Closing Cash Report's GL Entries table showed only the one account its
denomination row knew about; now shows both the debit and credit account
of each voucher (backend now returns debitParty/creditParty), matching
what My Vouchers already shows for the same entries
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Add Balance Sheet report and disabled-features accounting config
- Point menu-access tenant header and env.js/environment.ts tenant identifier
at env config instead of hardcoded 'default'/'lincpay' literals
- Surface the real backend error (not a generic "no reference id") when an
OTP send fails in contact-otp-block
- Fix branch-day "₹null" display bug (null vs undefined) and add a guard
blocking a branch's first-ever day open before cash denomination migration
- Dynamically size the denomination count input and block re-opening an
already-open business day from Migrate Cash Denomination
- Lock the denomination-managed cash GL row in Migrate Opening Balances
(read-only, with a link back to Migrate Cash Denomination)
- Remove duplicate Cancel/Submit action bars on the Share Product and
Savings Account creation preview steps; align Previous into the same row
- Hide "Apply Collection" on a share account once its advance collection
is already settled (further purchases go through Apply Additional Shares)
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds the frontend half of the per-tenant menu-access ceiling
(TenantMenuAccessApiResource on the backend): a bank cannot show a top-nav
section the platform operator has capped, no matter what any role inside
that tenant grants itself — closing the gap where a role carrying
ALL_FUNCTIONS (as "Clerk" was found to, in two tenants this session)
bypassed every ordinary MENU_.../SIDEBAR_... permission check.
- tenant-menu-access.service.ts: loads the current tenant's list once,
into a plain Set (not an Observable the directive would have to
subscribe to, since mifosxHasPermission's setter runs synchronously).
A failed load is treated as "nothing disabled" so a network hiccup on
login never hides the whole nav.
- has-permission.directive.ts: checks the tenant's ceiling first, ahead of
the ALL_FUNCTIONS bypass — that ordering is the actual fix.
- shell.component.ts/html: the nav now waits on the list being loaded
before rendering at all, so a disabled menu is never shown and then
hidden a moment later.
- New standalone platform-admin/menu-access screen (#/platform-admin/
menu-access), reachable without logging in — its own X-Api-Key is the
real boundary, checked on the backend, not this route. Lets the
operator pick any tenant and toggle its menu list. Redesigned per
request: full-width layout, icon-matched toggle tiles (same icon per
item as the real nav), live enabled-count, connection status.
- Loan Origination and Investment now use their own MENU_LOAN_ORIGINATION
/ MENU_INVESTMENT codes (see backend 0542) instead of sharing
MENU_ADVANCES / MENU_RBI, so all 27 nav items are independently
controllable from this screen.
Also: src/assets/env.js — restored 'socity_bank' to
fineractPlatformTenantIds. The tenant now exists in the tenant-store
database; the comment explaining its earlier removal was stale.
Brings in the Product Approval feature (anshul.rathore) — a unified Approvals
screen for Loan/Savings/Current/Share/FD/RD/Charge product requests:
- Merges two existing pending-request sources into one list: staged product
edits (m_saving_product_temp, via /{producttype}/pending) and native
maker-checker entries (/makercheckers) for product CREATE/DELETE and
LOANPRODUCT/CHARGE of any action.
- Checker Inbox no longer lists product requests at all — they now live only
in Product Approval, so a checker isn't checking two queues for the same
thing. Clicking a non-product row now navigates straight to that entity's
own view page when one exists, instead of always opening a detail dialog.
- View Checker Inbox dialog gains a caller-supplied heading (used when opened
from Product Approval) and a notice steering staged product edits back to
Product Approval instead of being actioned in place.
- Route renamed pending-savings-products -> product-approval, with the old
path kept as a redirect for existing bookmarks/links.
8 files conflicted with dev's own recent Checker Inbox work (popup-based
detail view, e8097bc2/63134f17) and were resolved by hand, keeping both
sides' real functionality rather than picking one branch wholesale:
- product-edit-diff-dialog.component.{ts,html,scss}: kept dev's diff dialog
(resolves GL account ids to names, aliases fields like currencyCode against
the stored product, normalises the two date shapes the API uses) over
maker-checker's simpler raw-value version.
- pending-savings-products.component.{ts,html}: kept maker-checker's full
isPendingEdit()-based dispatch (dev's version was a strict subset of it).
- view-checker-inbox.component.{ts,html,scss}: kept dev's per-entry Delete
action and maker-checker's recursive Command-payload tree renderer and
custom heading side by side.
Also recovered two regressions the merge introduced silently (no conflict
markers, so `git merge` gave no warning):
- tasks.service.ts lost deleteMakerChecker() entirely — restored.
- Checker Inbox's bulk Delete action (button, deleteChecker()/
bulkDeleteChecker(), and its .cv-btn-delete style) was dropped across three
files — restored to match dev's pre-merge behaviour exactly.
And one duplicate the merge produced without a conflict marker: two
independent viewEntry() implementations landed in checker-inbox.component.ts
(TS2393, caught at build). Kept maker-checker's entity-view-page-routing
version — a superset of dev's dialog-only version — and dropped the duplicate,
along with a leftover diagnostic console.log.
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.
Two share-account charge bugs found while chasing why a share account's
entry-fee charge wasn't showing up in the "Apply Share Advance
Collection" flow:
- create-shares-account.component.ts / edit-shares-account.component.ts:
the submit payload built charges as { chargeId: charge.id, amount }.
A charge seeded from the product's own default template arrives as
ShareAccountChargeData, where the real charge id lives in `chargeId`
and `id` is null (no saved ShareAccountCharge row yet); only a charge
picked from this step's own "Charge" dropdown (plain ChargeData) has
it in `id`. So `charge.id` alone silently produced chargeId: undefined
for the common case (accepting the product's own default charges),
Angular's JSON.stringify dropped the undefined field, and the backend
received a charge with no id to attach -- the account got created with
zero persisted charges no matter what the product had configured.
Verified via the actual submitted command JSON in the DB
(charges:[{"amount":200}], chargeId missing entirely). Fixed by
falling back to charge.chargeId || charge.id in both places.
- shares-account-charges-step.component.ts: on the "edit an existing
account" flow, the account's real saved charges (possibly a correctly
empty array) get patched into chargesDataSource once the shared
currencyCode control settles, but that patch never cleared the
`pristine` guard. ngOnChanges fires again on the same input-update
cycle (the sibling Terms step, declared earlier in the wizard, patches
currencyCode from its own ngOnChanges, which synchronously triggers
this component's currencyCode subscription, and Angular then runs
this component's own ngOnChanges right after) -- with `pristine` still
true, that re-seeded chargesDataSource from the product's *current*
default template, silently overwriting the real (possibly empty)
saved state. Set pristine = false once the real charges are patched
in, so a later ngOnChanges can't clobber it.
Also: offices.component.ts now distinguishes an office delete that
actually completed from one that was queued for checker approval
(response.rollbackTransaction, the same signal every other
maker-checker-eligible screen in this app already keys off), instead of
always claiming "Office Removed" regardless of which happened.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The tenant selector (mifosx-tenant-selector, already wired into the login
page) hides itself whenever fineractPlatformTenantIds resolves to a single
entry -- and env.js only ever listed 'abc_bank', so the dropdown never had
a reason to show even though Socity_bank and, as of this session, Default
Bank are all live, reachable tenants.
Lists all three identifiers exactly as registered in the tenants table
(default, abc_bank, socity_bank) so a user can actually pick which bank to
log into instead of being stuck on whichever one was hardcoded.
The manager's Closure Review dialog only showed the amount once the request
reached APPROVED or later -- closing_amount/rounding_amount/cashier_disbursed_amount
were null on a PENDING record, since the backend only filled them in at
approve() time. A manager reviewing a still-pending closure saw client name,
payout mode and token, but no figure to actually approve.
The backend now populates those columns at submission (interest is posted
for real at that point, so the figure is already known -- see the matching
backend commit), so this just stops gating the amount card on
closing_amount != null and moves it to the top of the dialog as "Payout
Amount", shown for every status.
Also added: Closure Date ("Interest Posted As On"), Transaction Id once
close() has run, and a "Handed Over By Cashier" section once disbursed --
so the full lifecycle of a closure is visible from one dialog instead of
needing to cross-reference the account's own transaction history.
Ticking "Close this account" on the Transaction Entry Action popup called
GET /clerk/closure-requests/preview/{id} -- a dry run that computed the
payout and immediately rolled it back, so the account's own balance stayed
unchanged until a manager later approved the closure.
Wired to the new POST /clerk/closure-requests/post-interest/{id} instead
(see the matching backend commit), which posts the interest for real and
returns the account's actual resulting balance. Renamed
ClerkClosureRequestService#preview to #postClosureInterest to match, and
reworded the popup copy and loading state so it no longer implies posting
happens later at Save ("posted to the account as of ..." instead of
"calculated to ... and posted the moment you press Save").
Also corrected a stale comment on the balance-check bypass for a pending
closure: it used to justify the bypass by saying interest was NOT YET
posted, which stopped being true the moment the checkbox itself started
posting it for real.
The dialog rendered but read badly: the heading appeared twice, and every field
ran together onto one line ("ID: 125Status: User: mifosAction: DELETE").
Cause was the global flex-40/flex-60/flex-fill utilities the template used --
they are sized for a full-width page, so inside a 680px dialog the label and
value columns collapsed and wrapped into each other. Replaced them with a
self-contained label-above-value grid that reflows to one column when narrow,
so the same markup reads correctly as a page and as a popup.
Also: moved the heading into the shared header so it is rendered once in both
modes, gave the actions real buttons instead of Material raised buttons styled
by two global overrides, put DELETE in a red tag so a destructive entry is
visible at a glance, and dropped MatDivider/MatDialogModule from imports now
that the markup no longer uses them.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Clicking a row navigated away to its own page, costing the checker the list and
whatever search they had set up. It now opens in a dialog over the list, the
same pattern the Disbursement and Closure Requests tabs already use.
ViewCheckerInboxComponent gained the optional MatDialogRef/MAT_DIALOG_DATA pair
rather than being duplicated, so the direct route still works for a bookmarked
link. Two differences follow from being a dialog:
- the list rows carry only summary fields, so the detail (which is what has
commandAsJson) is fetched here; by route it stays resolver-provided. The
template reads checkerInboxDetail.* unguarded, so it is now behind an @if
with a loading state -- otherwise a dialog would render against undefined.
- commandAsJson is absent on some entries (a DELETE carries no payload) and
JSON.parse(undefined) throws. By route that broke the page; in a dialog it
would have left an empty shell open. Parsing is now guarded.
The list only reloads when something was actually actioned, since reload()
re-navigates the route and would otherwise discard the checker's search on a
plain close.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Brings in the UI side of maker-checker for users and roles: a Pending User
Edits tab with a compare dialog, user/role create-edit-view wired to the
pending-request flow, plus keyboard shortcuts and inline-create dialogs.
Both conflicts resolved in dev's favour:
.env.ts — auto-generated build stamp; dev's (260901) is the newer one.
share-product-general-tab.component.html — dev had deliberately removed the
per-product Dividends button, leaving a comment explaining that dividends are
declared society-wide from Share Products -> Dividends because the board
resolves one rate for the year rather than one per product. The branch simply
predates that change, so taking its side would have resurrected a button that
was removed on purpose.
checker-inbox-and-tasks.component.html and tasks-routing.module.ts auto-merged
cleanly, with both the new Pending User Edits tab and the existing Closure
Requests tab intact.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The whole DD-against-cash path was already written and reachable only by a
cashier -- isDdCashGlRow() gates on a cash payment type against a GL account,
onSave() makes the cashier count Face Value + Charges + GST exactly and
enforces the admin DD limit at intake, and buildDepositPayload() persists that
breakdown so the Sponsor DD issuance screen reads it back after approval. None
of it could be selected, because DD was missing from cashierTypOptions.
Also adds the DD case to onTypChange, without which selecting DD set no
defaults at all: it needs Cr (a draft is bought with cash, so money comes in),
a cash payment type, and AC.TP = GL, which are the three things isDdCashGlRow()
looks for. Missing any of them, the DD Charges & GST panel never appears and
the row posts as an ordinary entry with the charges silently dropped.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Replaces the one-click Close action on the savings account page (removed from
the Danger Zone menu) with a maker-checker flow, since closing an account pays
real cash out of a teller's drawer.
Clerk: an Action button on Transaction Entry, shown once an ACTIVE savings
account is loaded. Ticking "Close this account" previews the payout -- balance
plus interest calculated to today by the same code the closure itself runs --
and Save drops that figure into the slip's AMOUNT. The clerk then fills
TOK. NO. on the slip and presses Save, which raises the request. Token and
narration deliberately live on the slip, not in the popup, so the closure is
entered like any other transaction.
Manager: a Closure Requests tab in the Approval Center, reviewed in a popup
dialog (matching Disbursement Requests) rather than a separate route.
Cashier: the closure token is recognised at the counter alongside withdrawal
and dividend tokens, auto-filling the rounded cash figure, locking it, and
closing the account once the denomination is counted.
Save-path fixes, all of which silently blocked a valid closure:
- amount came from the denomination total whenever clerkMode was false --
which it is for any route other than the Clerk Dashboard wrapper -- so the
calculated payout was replaced by zero
- the balance check rejected the payout because it legitimately exceeds
today's withdrawable amount: it includes interest close() posts before
withdrawing. Min-balance, withdrawal-facility and clerk-side denomination
checks do not apply to a closure either
- on the cashier side the account is already CLOSED, so accountDetails is a
stub with no balance and the same check reported "Withdrawable 0.00"
- the closure branch had to precede the plain clerk-withdrawal branch: a
closure is a full-balance withdrawal, so that branch would have swallowed
it and the account would never have closed
- onSave's one silent return now says what is missing, instead of leaving
Save looking like a broken button
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
- Register the missing edit-details route so the Share Account "Edit Details"
maker-checker screen (already built) is actually reachable, and remove the
stale hardcoded disable on its menu entry.
- Fix Terms step race: Default Savings Account, Total Shares and Application
Date now display correctly in edit mode instead of racing an async
product-template fetch or reusing pending-application-only fields.
- Show a client's linked share account number on the Savings Account General
tab.
- Replace the inline diff panel on Pending Share Account Edits with a popup
compare dialog (mirrors the savings equivalent), showing only fields that
actually changed.
- Redesign Pending Share/Savings Account Edits, Share Withdrawal Requests,
Dividend Requests and Share Addition Requests with a consistent header,
search box and (where the data supports it) date-range filters, matching
the existing Withdrawal Requests screen.
- Savings account creation shows a required "Default Share Account" picker once Share Linking is
enabled, populated from the client's active share accounts; submits shareAccountId alongside it.
- Fixes a real data-loss bug on Share Account creation: the Charges step re-seeded its table from
the product's default charges on every ngOnChanges firing (e.g. stepping back to Details and
forward again), silently discarding a charge the clerk had already added, edited, or removed - a
pristine guard existed for exactly this but wasn't checked in ngOnChanges. Now it is.
- Removes the hard "required" on Share Account creation's Default Savings Account field, matching
the backend now accepting a share account with no linked savings account.
- New /accounting/migrate-cash-denomination screen: counts a branch's opening cash into notes and
coins, checks it against (or defines, if unset) the Cash GL account's balance, and opens the
branch's first business day with that same count - the vault-side counterpart to Migrate Opening
Balances, kept under Accounting rather than Branch Ops/Cashier so it isn't reachable by mistake.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Replaces the flat, hard-to-scan opening-balances form with a stepped layout: branch pick, a
clearly-explained contra account, a pinned Debit/Credit balance status (green "Balanced" vs red
"Out of balance by X"), and account rows grouped by type with a mobile-responsive grid. No
behavior change - same form controls, same validation, same submit flow.
- env.js: default/available tenant switched from default,socity_bank to abc_bank.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
'Fund Transfer' and 'Enter Bank Transfer' are the same flow under two TYPE labels -- onTypChange()
already defaults them identically and the auto-mirror-row logic already treats them as equivalent --
but the Resolution No./Meeting Date fields and onSave()'s clerk-transfer submission gate only checked
'Enter Bank Transfer'. Picking 'Fund Transfer' for a Share row silently hid the board-resolution
fields and skipped submitShareRedemptionTransfer() entirely, falling through to the wrong save path.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Add Approval Center tab "Share Addition Requests": lists every pending additional-share tranche
across all accounts (backed by the new /v1/shareadditionrequests endpoint), with a detail popup
showing the board resolution and the route-specific proof of funding (voucher(s) for cash, or the
linked savings account for savings). Approve/Reject call the same native
approveadditionalshares/rejectadditionalshares commands the account-page buttons already used.
- Remove "Debit from Savings" dialog/button and the "Share Savings Debit" Checker Inbox tab -- zero
rows ever recorded on either tenant since it was built.
- Remove "Approve Additional Shares"/"Reject Additional Shares" from the account-page menu now that
every tranche is reviewed from the centralized queue instead.
- Harden SharesButtonsConfiguration.removeButton(): a not-found name fed to splice(-1, 1) was quietly
deleting the LAST button in the array instead of doing nothing -- removing the two menu entries
above would otherwise have silently broken the rest of the Active-account button bar.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- 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>
Account Statement is no longer a jsPDF file that downloads the moment the
dialog opens. It now shows a live, on-screen preview styled the same way
the working Passbook screen already is (bank header, branch line,
account-details band, balance strip, transaction table), with its own
date-range filter, and only prints via the browser's print dialog on an
explicit click -- exactly the same clone-into-a-popup-window mechanism
Passbook already uses, so "Save as PDF" is the reader's own choice rather
than something forced on open.
Both Passbook and the new Statement preview pull the bank name, license
number, and branch name/address/IFSC/MICR from Institution Profile and
Branch Profile instead of a hardcoded bank name -- a printed passbook or
statement now actually identifies which bank and branch issued it. Cheque
Book's own issuance detail screen gets a matching "Print" action, laying
out a one-page issuance-slip PDF from data already on that screen (which
book/series, leaf range, issued-to account, issue date).
Cash Hold and Clearing Hold on the Transaction Entry balance strip were
both hardcoded 0.00 placeholders; they now read the account's real
hold-category breakdown, and a stray "Freeze Amount" placeholder a few
rows up is wired to the working getter that was already sitting right
next to it.
A clerk withdrawal's own terminal status is WITHDRAWN, not APPROVED --
the Day Book screen had the same status-string gap the backend GL report
did: neither its running CR/DR totals nor its status badge recognized a
completed withdrawal, so real money that had gone out never moved the
totals off zero. The Closing Cash Report's GL Entries panel also never
refreshed for a newly picked date once it had already been opened once --
"Load" hid the panel instead of refreshing it, leaving a stale, wrong-date
table under a header that had already relabelled itself correctly.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The Day Open form's note/coin table started at zero even though the
branch's own closing count from the day before was already on record --
whoever opened the day had to re-key numbers that were already known.
It now auto-fills from that closing count, flags any row a manual edit
moves away from it, and shows a live Tallied/Short/Excess comparison
against it -- so a short or excess opening count is visible before the
day is opened, not discovered later. A reason is required once a mismatch
exists, matching the new backend enforcement.
Also fixes the register table's date chip wrapping onto two lines when
the column narrows.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Branch Day open/close now captures a denomination-wise count (carried
forward automatically to the next day), and shows an auto-fetched EOD
summary at close time -- vault + every cashier's position, a branch-total
reconciliation against the book figure, and each cashier's
reconciliation/settlement status and transaction count -- so closing the day
no longer means separately checking Vault Position and every cashier's own
screen by hand. New Vault Position screen (branch-ops menu) mirrors Cashier
Position for the teller/vault. Cash Transfer now shows the vault's live
per-denomination availability while counting a handout, with a client-side
warning before it can be over-counted.
New Organization screens for Bank Profile, Branch Profile and Clearing GL
Configuration, wired into the Organization landing page and the
previously-dead "Bank Profile" admin menu button.
Cashier Transaction Entry: TYPE is now Receipt/Payment only (cash-only TXN
TP.) on the cashier side, with no change to the clerk dashboard's own
Withdrawal Slip/Cheque/Disbursement/Enter Bank Transfer/DD flow beyond
adding a new Fund Transfer type alongside Disbursement for a GL credit that
isn't a loan payout. Neither TYPE nor TXN TP. offers a blank placeholder
option anymore -- a new row starts on a real default instead. Footer no
longer polls the business-date config for cashier/clerk roles, who never
have permission to read it.
Disbursement & Transfer Requests: "Review" now opens the review screen as a
popup instead of navigating to a separate route, refreshing the list on
close; the review screen recognises the new Fund Transfer request type
too, and its non-functional "+ Disbursement Review" tab-styled label is now
a plain heading.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a Products > Facility Charge Mappings screen so each of the 16 facility
toggles can be pointed at a real charge, backing the mapped-charge validation
added on the backend. Bulk-approve on the pending accounts screen now chains
straight into activation (matching the single-account approve flow) instead
of leaving accounts sitting in Approved; the same screen's Confirm button no
longer stays disabled on pre-filled but untouched dialogs. Add Charge is
hidden on not-yet-active savings accounts, and Transfer Funds is disabled
entirely pending a proper transfer flow. The pending savings-account edit
"Proposed Changes" panel is now a MatDialog showing only the fields that
actually changed, replacing the old always-open inline diff table. The teller
transaction-entry Payment Type dropdown is filtered to Cash/Transfer only,
mirroring the backend's retirement of the other system-defined payment types
so share withdrawal and GL transfers now settle the same way real transfers
do.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Four independent, self-contained changes bundled from this session's work:
1. Auto-derive Senior Citizen / Minor / Customer Segment instead of manual entry
Senior Citizen was a manual, staff-editable checkbox on FD/RD account
creation with no validation against the client's actual age -- this let
non-senior clients get the senior-citizen interest rate by mistake (found
twice on live test accounts, where m_savings_account.is_senior_citizen
was true despite the client being confirmed non-senior at the client
record level). Likewise "minor" client classification was hardcoded to
the age-18 threshold with no single source of truth, and FD/RD account
creation's "Customer Segment" (Individual / Non-Individual) had no
connection to the Individual/Non-Individual Legal Form already captured
at client creation.
- New src/app/clients/shared/client-age.util.ts centralises age/DOB
derivation: MINOR_AGE_THRESHOLD (now 10, was 18), SENIOR_CITIZEN_AGE_
THRESHOLD (60), AGE_OF_MAJORITY (18, kept separate from the minor
threshold -- majority date math is unrelated to the minor/adult
classification threshold), calculateAge/isMinorAge/isSeniorCitizenAge/
isIndividualClient/deriveSeniorCitizenStatus.
- FD/RD interest-rate-chart steps: Senior Citizen checkbox is now derived
from the client's DOB (age >= 60, individual clients only) and
disabled for manual editing; a hint explains why it is checked/
unchecked.
- Client general step and all four account-details-steps (savings,
current, FD, RD): replaced hardcoded 18/60 literals with the shared
helpers; "Must be below 18" hints now read the actual threshold.
- FD/RD account-details-steps: Customer Segment auto-selects to match
the client's Legal Form (exact match, not substring -- a substring
match would misclassify "Individual" as matching "Non-Individual").
- RD preview step: fixed a pre-existing display bug that always showed
the product's default Customer Segment instead of what was actually
selected on the account.
2. Fix wrong Account Name / Account Type on Disbursement Review screens
Clerk disbursement review and "My Disbursement Requests" showed the
account NUMBER instead of the holder's name, and always labelled the
account type "SAVINGS" regardless of the real account type (FD/RD/
Share/Loan), because transaction-entry.component.ts's account-type
mapping only checked for CA/CB and its account-name fallback chain
never tried clientName. Added creditEntryAccountType() covering
GL/CA/CB/FD/RD/SHR/LA, and accountTypeLabel() display helpers on both
review screens.
3. Stop reversed transactions from distorting displayed running balances
Passbook and Transactions tabs were including reversed transactions in
their client-side running-balance recalculation, so a reversed posting
(visible struck-through) still shifted the balance shown for every
transaction after it. Both now filter out txn.reversed before computing
running balances; Transactions tab also defaults "Hide Reversed" to on.
4. New Interest Schedule dialog on the FD account view
Added custom-dialogs/interest-schedule-dialog, opened from the FD
General tab, showing the account's period-by-period interest schedule.
Excludes src/environments/.env.ts (auto-generated build version/hash
stamp, regenerated on every build -- not meaningful to hand-commit).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
WHAT THIS CHANGES
==================
Frontend counterpart to the backend FD in-place renewal, senior-citizen
rate, and Payment action work.
1. RENEWAL HISTORY TAB (new) -- fixed-deposit-account-view/renewal-history-tab/.
A vertical timeline, one card per term of the FD, oldest first. Backend
data arrives as a list of lowercase-keyed maps (Postgres unquoted SQL
aliases), which the component normalises. Includes term-rate-chart-dialog,
a popup showing one term's full rate-by-tenure chart, including the
senior-citizen column, with an "Applied" badge on the rate that was
actually used. Route added in fixed-deposits-routing.module.ts, tab
link added in fixed-deposit-account-view.component.html (shown only
when the account has renewal history).
2. PAYMENT DIALOG (new) -- fixed-deposit-account-view/custom-dialogs/payment-dialog/.
Card-based picker for the four supported closure types (Transfer to
Savings, Re-Invest Principal and Interest, Re-Invest Principal Only,
Partial Re-Invest), with Withdraw Deposit filtered out client-side.
Fetches its own template via a new fixedDepositsService method
(getFixedDepositsAccountPaymentTemplate, command=payment) rather than
reusing the Close template, since the Payment template is the only one
the backend includes PARTIAL_REINVEST in.
The Partial Re-Invest amount cap is date-dependent: the backend bounds
it against the account balance AFTER posting interest to the chosen
closed-on date, which lands on the maturity amount on or after
maturity and on the current balance before it. The dialog mirrors this
(reinvestCap / processingOnOrAfterMaturity) so the shown split actually
adds up and the client-side validator agrees with the server. This was
wrong in an earlier pass of this work (compared against a fixed figure
regardless of date) and was caught and fixed via a real reconciliation
check (77000 + 23000 did not equal the displayed total) before this
commit.
Added: a loading-failure state (previously the spinner ran forever on
a failed template fetch), an inline submit-error message (previously a
failed POST left the dialog open with no feedback), an empty-savings-
accounts hint, and accessibility attributes on the option cards
(role="radio", aria-checked, a visible check icon, focus-visible
outline) since selection was previously colour-only.
3. TRANSACTIONS TAB -- merges synthetic "FD Renewed" marker rows into the
real transaction list, since an in-place renewal posts no actual
ledger transaction and would otherwise look like the balance changed
for no reason.
4. INTEREST RATE CHART TAB -- added the senior-citizen rate column.
5. DEPOSIT CERTIFICATE DIALOG -- lists the full renewal history on FD
certificates. renewalCount is renewalHistory.length - 1 (the first
row is the original term, not a renewal); an earlier version of this
used the raw row count and overstated the renewal count by one on a
customer-facing document, caught and fixed before this commit.
6. CLIENTS GENERAL TAB -- fixedDepositAccountsForDisplay folds a renewed
FD's superseded terms out of the account list (each renewal used to
show as two unrelated accounts, one Closed and one Active). Memoised
on the source array's identity so it does not rebuild, and rebind the
table, on every change-detection tick. Only rewrites FD rows; Savings,
RD, Current, and Share account rows pass through this getter
untouched, and the RD/Savings sections of the template were left
bound directly to the original savingAccounts array.
KNOWN CAVEATS
=============
- This depends on the paired backend commit (same date, "feat(deposits):
FD in-place renewal, senior-citizen rate persistence, and Payment
action"). Deploying this frontend without that backend change means
the Payment dialog and Renewal History tab will call endpoints that
do not exist yet.
- Renewal-history rows rely on the backend returning lowercase column
keys (a Postgres-specific behaviour of unquoted SQL aliases via
JdbcTemplate). Confirmed correct against this project's Postgres
dev database; if this project ever runs on a different database
engine, that assumption would need re-checking.
- src/environments/.env.ts is intentionally excluded from this commit;
it is a local build-version stamp file that should never be
committed.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The pending-product-edit comparison listed every field the edit form posted -- around fifty,
nearly all unchanged -- as an inline panel under the table, which buried the handful a checker
actually needs to look at. It is now a dialog listing only fields whose value differs.
Values are resolved to what the maker saw rather than what the payload carries: enum and
GL-account ids become their labels, dates in either API shape read the same, and empty
values no longer register as changes. Without that, option fields compared an expanded
{id, value} object against a bare id and reported every one of them as changed.
Fixed Deposit accounts created by a reinvestment now show the account they came from, and the
matured account shows the one it went into, each linking to the other.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Fixed and Recurring Deposit wizards now bidirectionally sync the Product tab's
linked-account selection with the new Terms tab's Transfer-to-Savings account,
disable the Withdraw Deposit maturity instruction end-to-end, and card-style
the Transfer to Savings picker to match the existing linked-account UI. Adds
a printable FD/RD deposit certificate from the account view page, following
the existing letter-mgmt certificate pattern.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
An unresolved git stash conflict had been committed as-is, leaving
literal <<<<<<< Updated upstream / ======= / >>>>>>> Stashed changes
markers inside the template. Angular rendered them as plain text right
in the create-client form. Kept the blur-triggered capitalizeControl()
version (matches First/Middle Name) and dropped the now-unused
formatName() left behind by the other side of the conflict.
Matches the backend change that stopped auto-depositing money at
activation: removes the opening-balance field from every Activate
screen (Savings, Current, FD, RD) since funding now happens as a
separate deposit afterward, and removes the Digital-Facility step from
every Create wizard since every facility starts disabled by default
and gets turned on later through Edit Nominee & Features.
Also merges Approve+Activate into a single action for Savings,
Current, FD and RD accounts -- one click takes the account straight to
Active instead of two separate screens.
Replaces the in-memory mock (LOAN_APPLICATIONS array + seeded RNG, reset on
every refresh) with real Fineract-backed persistence: a new
LoanOriginationService for CRUD plus one API call per stage transition, a
loan-fineract-bridge that creates a real loan account (create + approve +
disburse) at disbursement for Existing Customers, and file uploads through
Fineract's generic document store keyed by a stable checklist slot so
"On file"/View controls survive a reload.
Also fixes several gaps found while verifying full-cycle persistence:
- CIC charge-account selection never saved (missing persist() call)
- Co-borrower relationship/monthly income lived in local-only component state
instead of on the application, so they reset on refresh
- Field Investigation "View Full Details" showed local-session photos only;
stored photos are now downloaded and shown as real thumbnails
- "Assign Field Officer" was free text; now a dropdown of real CBS loan
officers pulled from /staff
- site photos and cheque/signature images now open in the same zoomable,
pannable lightgallery viewer used elsewhere in the app
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Guarantor must be a real existing client with a verified active share account, with clickable share-account chips
- Loan Committee Approval now requires Resolution No./Date plus a full application report before approving
- Loan Committee gets its own pre-filtered pipeline view via a menu link and stage query param
- Legal Approval stage gets a multi-file document upload checklist with add-more support
- CIC PDF parser: item-level score detection before line-based fallback, fixing font-size-driven line-merging misdetection
- New Interest & Share Rate Chart tab: per-product interest/tenure bands and per-amount-slab Share Capital linkage requirements
Extracts score, accounts, DPD payment history and enquiries directly from an
uploaded bureau PDF (position-aware parsing, so blank DPD months are handled
correctly) instead of always showing a simulated report, falling back to the
simulated analysis when a file can't be read.
- New Application: add Product Type (Term Loan/Overdraft) driven by product eligibility.
- KYC: 3-year ITR capture with exceptions, product-specific document checklists with officer-added
custom docs, Housing Loan co-owner Aadhaar/PAN capture+verify in a popup dialog.
- Income & Affordability: editable income/amount/tenure with product bounds validation, 40% EMI
rule, and a full co-borrower flow (relationship, salary slips, combined-income eligibility).
- Bank Statement upload auto-opens a full CSV-driven cash-flow/FOIR/risk analysis dialog.
- CIC report upload auto-opens a bureau-style credit report analysis (score gauge, accounts,
DPD history, enquiries) generated from the application's own credit score.
- Field Investigation reworked into per-address cards (Home/Office/Property/Shop) with officer
assignment, 48-hour SLA tracking, GPS + multi-photo capture, verify/reject with remarks, a
full-detail popup, real Fineract addresses for existing clients, and a calculated property
valuation (market/guideline/realizable value, LTV).
- Personal Discussion: meeting scheduler (date/time/mode/officer) gating the discussion report,
plus a full Application Summary Report PDF (KYC, CIC, FI, valuation, stage history) for the
meeting.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Add standalone RBI Eligibility Checklist and RBI Rules Reference pages (11 real RBI-circular
based rules: age-at-maturity, area of operation, PSL, director/related-party, wilful defaulter,
exposure norms, LTV/margin, fair practices code, prepayment charges, own-shares security,
insurance bundling), wired into the Loan Origination menu.
- Bridge the mock Loan Origination Pipeline to real Fineract data wherever an application is
raised against a real Existing Customer: client search in the pipeline intake form, real Share
Member accounts (with a details popup), and real KYC (Aadhaar/PAN verified status + masked
numbers + document image view, generic document lookup for Income Proof/Bank Statement/
Electricity Bill) on the Application Detail page.
- Add local-only capture UI for New Customer / no-account applications: front/back document
images with crop + simulated Aadhaar OTP / PAN verification, employment-type-aware income proof,
and an expiry-validated electricity bill upload.
- Add an EMI Calculation Basis breakdown (principal, rate, tenure, total interest/payable, and the
substituted reducing-balance formula) to the KYC stage's income assessment.
- Add a CIC/Credit Bureau Check consent flow: a generated declaration letter (print for Branch,
share for BC/Self-Apply), gated on the signed copy being uploaded before the credit score can be
checked, plus a CIC check charge collected either by debiting a real linked account or via a
mock payment-link flow for customers with none.
- Let the stage stepper jump directly to any already-reached stage (forward or backward) via a new
furthestStageIndex, without losing any data already recorded on the application.
Cash claims now require a token at claim submission; a cashier redeems
it at Transaction Entry to record physical hand-over, mirroring the
existing clerk-withdrawal-request flow -- no double-disbursement, and
the manager never hands over cash directly at approval time.
Also: dividend-claim tokens fall back through the same TOK. NO. lookup
used for withdrawal requests, silenced against the global error
interceptor since the caller already handles every outcome; the account
summary card now shows "Dividend Claim" instead of a misleading "A/c
Savings" label when resolving one; and cash amounts are floored to
whole rupees client-side to match cash's whole-rupee denominations.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Frontend counterpart to the backend dividend rework:
- Create Dividend screen auto-computes the amount from real bank profit x officer
percentage, blocks overlapping declaration periods, and adds a Total Dividend Paid
summary card.
- View Dividend page modernized and reusable as an embedded popup from the new
cross-product "Dividend Requests" approval-center tab.
- New consolidated Dividend Dashboard: summary stats, every declaration and its
status, locked-dividend-vs-overdue-EMI matching with a proactive apply-to-loan
action, full 3-year lock history, and a maker-checker claim panel letting a clerk
split a member's unclaimed dividend across an overdue loan, savings credit, or
cash for a manager to approve.
- Menu/routing consolidated under Share > Dividend Management; removed the
now-unreachable Failed Dividend Payouts page and its home-dashboard alert once the
backend stopped needing a retry path for stuck payouts.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replaces the auto-submit-closure-request behavior with an immediate
account close, in the same approval action, when a withdrawal brings
shares to zero — matching the backend's new single-step close-on-
approval flow. Removes the now-unneeded Share Closure Request feature
entirely: dedicated create/list components (Clerk Dashboard + Approval
Center), routes, nav links, and the "eligible for closure" banner on
the Share Account view.
Also adds a clear "this will close the account" notice wherever a
withdrawal would zero out the account's shares — the standalone Share
Withdrawal Request page (submit + review) and Transaction Entry's
Share Redemption Transfer confirm dialog — styled as an amber warning
callout rather than a plain info line. Trims that confirm dialog to
just the required details (dropped the redundant ECS A/C No. line and
the validation-checklist block) and compacts its overall size.
Systematic file-by-file audit of demo-backup against dev to find any
remaining instances of the same silent-drop pattern from the earlier
merge (git's 3-way auto-resolve keeping demo-backup's side wherever it
had independently touched nearby lines, even when dev's side was a
genuine, unrelated addition). Restored:
- clients.module.ts: missing ClientFamilyMemberChildDialogComponent
registration (component existed but was never wired in)
- client-family-member-dialog: full children-management flow (checkbox,
form array, child dialog integration, view/edit summary blocks)
- edit-client: FIR-exception flow for inaccessible old mobile numbers,
and a hardened detectSensitiveFieldChanges() (null-guard, phone-digit
normalization, dirty-checked comparisons to avoid false-positive
Verify-Contact-Change prompts)
- shell.component.ts: withdrawal-review URL matcher extended to cover
the Share Withdrawal Request review route
- fiu.component.html: AML alert status filter and monthly CTR reports
table UI (backing logic already existed unused in the .ts)
- Shares module: Passbook tab (component existed but had no route or
tab link), running-balance/resolution columns on the transactions
tab, subscript-sizing fixes and a pill-style filter-bar redesign on
Share Holders
- Savings/Share product accounting steps: Payment-Channel-to-Fund-
Source mapping section, and Share Reference account restructuring
- pending-client-edits: email status badges + "View Email" button
(dialog component existed but nothing on this list triggered it)
Everything else that still differs from dev was individually verified
as either demo-backup's own independent work (Investment/Loan
Origination/NPA/RBI-OSS modules, the Approval Center tab-nav redesign,
AML/compliance review features, bank-name rebrand in demo seed data)
or purely cosmetic formatting differences — left untouched.
This entire feature — submitting a governed Share Withdrawal Request
directly from a Bank Transfer's DR(Share)/CR(linked savings) row pair
— was silently dropped from demo-backup during the dev merge's auto-
resolve, even though the feature files it depends on (clerk-share-
withdrawal.service.ts) were present. Restores: paymentTypesForRow()
(hides cash payment types for Share rows and their settlement CR
row), the SHARE NO./RESOLUTION NO./MEETING DATE fields (replacing
AMOUNT/CHEQUE NO./CHEQ. DATE for Share rows), rowSharePrices/
rowClientIds/rowLinkedSavingsAcNo tracking, submitShareRedemptionTransfer()
+ its confirm/submit flow, syncShareLinkedAmounts() auto-fill, the
Share-aware ecsAcNo/currentBalance logic, the Other Information panel's
Share-specific fields (No. of Shares Held, Market Price/Share,
Resolution No., Linked Savings A/C No.), and the SHR guard blocking
the generic Deposit/Withdrawal Slip flow for Share accounts.
Share accounts have no /accounts/share/{id}/transactions REST
sub-resource (transactions come embedded via ?associations=all) and
Share isn't a valid standing-instruction source account type on the
backend — hitting either endpoint 404s / errors. Restores the
txnFetchUnsupported/siFetchUnsupported config flags (present on dev,
lost in the earlier dev-merge's silent auto-resolve) that skip both
calls for Share, fixing the 404 seen when opening a Share account in
Transaction Entry.
The partial/suffix match fallback was gated on "exactly one row came
back from the list endpoint", but Share's /accounts/share list has no
accountNo server-side filter at all — it always returns the full
unfiltered list, so that guard could never pass and any non-exact
account number search (e.g. shortened digits) reported "Account not
found" even when the account existed. This fix (present on dev, lost
in the earlier dev-merge's silent auto-resolve) drops the count gate
and tries suffix-match then substring-match unconditionally.
The demo-backup merge's git 3-way auto-resolve dropped several hunks
without flagging conflicts, wherever demo had independently touched
adjacent lines: the KYC Exception feature (client-kyc-step, kyc-tab,
create-client, clients.service — checkbox, derivation logic, banners,
contact-log endpoints), TDS report routes/menu links (reports-routing,
shell), the Form 121 client tab (clients-routing, clients-view), the
kyc-management exceptions dashboard, and the Form 121/15G-H register's
real-data view integration. Restored by diffing demo-backup against
dev per file and re-applying each genuine gap while preserving
demo-backup's own independent work (Approval Center tab style, Loan
Origination/Investment menus, form-97-98/risk-review report routes).
Both dev and demo-backup independently added suppressMonthlyAnnualLink
and isHeadOfficeUser() at different points in their respective history,
so the merge's auto-resolve kept both copies instead of deduping,
causing TS2300/TS2393 build failures.
Files restored from dev during the demo-backup merge were missing the
standard license header (dev's copies predate that fix, which had only
been applied on the demo line previously). Also fixed pre-existing lint
debt surfaced by the edit: wrong component selector prefix and
constructor-injection pattern in client-family-member-child-dialog.
Brings in all of dev's latest content not present on demo-backup
(Share Withdrawal/Closure feature, TDS reports, KYC exception tracking,
client-edit-email-dialog, form121 tab, search-select) while preserving
demo-backup's own unique changes (wrapping Approval Center tab nav,
Loan Origination/Investment mega-menus). 36 files that a prior "ours
wins" conflict resolution had silently dropped were restored explicitly
from dev's tip.
Reverts all commits pushed to demo today (a5124ca3, 858c277a, a1a50ab8,
f72abb09, fcf66657) back to f8c532f7 as a single forward commit, without
rewriting history. All reverted content (Share Withdrawal/Closure feature,
TDS reports, KYC exception tracking, client-edit-email-dialog, form121 tab,
search-select) remains intact on dev and was verified identical before
this revert.
The "Merge dev into demo" commit silently dropped both top-level nav
entries (desktop and mobile variants) along with their entire menu
panels — Loan Origination's mat-menu and the whole Investment mega-menu
(~150 lines) — because dev never had these menus, so the merge picked
dev's shell.component.html wholesale for this file instead of combining
both sides' additions. The underlying feature modules and routes were
untouched, so this restores only the shell wiring, copied verbatim from
the pre-merge demo revision.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Clerk submits a closure request only once a share account holds zero
shares; manager validates (shares still zero, account active, no active
loan/guarantee, KYC/AML standing, maker!=checker) and approves, which
executes the real Fineract "close" command. The direct native "Close"
action is removed from the account menu — it silently force-redeemed any
remaining shares, bypassing the withdrawal approval flow entirely — and
replaced with an "Eligible for Closure" banner. When a withdrawal approval
brings a share account's holding to zero, a closure request is now
auto-submitted (still requires manager approval) so the clerk doesn't have
to separately open "New Share Closure Request".
Also fixes an unrelated build break introduced by a merged commit: a
missing `suppressMonthlyAnnualLink` property declaration, and two files
(branch-scope.service.ts, gl-reports-data.ts) that existed on `demo` but
were never brought into `dev` alongside the new TDS report components
that depend on them.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
backdrop-filter on the list-embedded review popup was making it a new
containing block for its own nested position:fixed dialogs (Validate,
Reject, Confirm-Submit), confining them to the popup's box instead of the
viewport — replaced the blur with a plain darker overlay. Also adds a
permanent Client Compliance card (KYC status, risk category, open AML
alerts) on the review screen so a manager can see it without opening the
Validate popup.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Clerk submits a governed share redemption request (shares, Board Resolution
No., Meeting Date, settlement Payment Type); Bank Manager reviews with a
live backend-validated checklist (account/GL state, not just submit-time
snapshot) before approving, which redeems the shares and settles the
linked savings account in one transaction. Adds a Passbook tab to the
Share Account view, a reusable search-select control, and a Savings
Product "Map Payment Types to Specific Funds" fund-source override (only
Loan Products had this before) so settlement can be GL-mapped correctly.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replace mat-tab-nav-bar with a plain wrapping pill nav so all 16 approval sections stay
visible and one click away, instead of being hidden behind Material's prev/next scroll
arrows on a single-row strip.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>