Navigation bar (shell.component.html/.scss)
- Restyle top-level nav items as compact tabs and add responsive
breakpoints (1400px, 1200px, 1080px, 880px) that shrink icon, caret
and padding so the full menu fits on smaller laptop screens.
- Long labels now carry a short form shown on narrow widths:
Loan Origination -> Loans, General Ledger -> GL, Sub Ledger -> Sub GL,
Reconciliation -> Recon, Documents Hub -> Docs Hub.
- Reports and Insurance menus are regrouped into titled mega panels
(reports-mega-panel, insurance-mega-panel) using deposit-menu-group
sections instead of one long flat list.
- No route was added or removed: all 64 menu links (Account Register,
Day Book, End of the Day, Form 97/98, Risk Review, Re-KYC, Dormancy,
Savings/FD Interest Posting, TDS, BOR, DIP lookups, digital payment
reports, CKYC, DICGC, Clerk Desk, ...) still point to the same routes.
Global mega panel styles (main.scss)
- Shared grid and overlay styling for every Material mega menu
(cdk-overlay-pane with a menu panel) plus a coloured top accent per
panel: admin, cashier, clerk, branch-ops, hrm, digital, reports,
share, others, npa, letter, insurance, ckyc and reconciliation.
- Fixed column layouts for the dense panels (NPA 3 columns,
Reconciliation 5 columns, Reports, CKYC).
Toolbar (toolbar.component.html/.scss)
- User account dropdown gets its own t-user-menu panel style and opens
towards the left (xPosition="before") so it no longer clips at the
screen edge.
- Restyled AI assistant menu cards.
Density and products page
- Material density lowered from 0 to -1 (mifosx-theme.scss) for a
tighter, more data-dense UI.
- Products page cards: wider container (1280px), smaller icons, fonts,
gaps and padding to match the compact look.
Loaders (index.html, loading-screen component)
- Boot splash in index.html and the fullscreen mifosx-loading-screen now
show the CBS Nexora logo image (assets/images/cbsnexora-logo.png)
instead of the generic four-square SVG and text title.
Lint clean-up required by the pre-commit hook
- Prettier formatting and stylelint auto-fixes (modern rgb() notation,
range media queries, shorthand properties, empty lines before rules).
- Merged duplicate selectors into their first block without changing
the cascade: the second .reports-mega-panel (top accent border) in
main.scss and the second ::ng-deep .ai-menu (AI card styles) in
toolbar.component.scss.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Show a Lottie-animated splash while the app bundle boots and dismiss it
once WebAppComponent initialises, plus a reusable mifosx-loading-screen
component with loading and error animations. lottie.min.js is served
from the lottie-web package instead of being vendored into src/assets.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Removes the FD Maturity Reports screen, its route and nav entry, and
the maturing-today section on Branch Day Closing — the backend report
and approval gate behind them are gone, and a matured deposit's final
interest already surfaces under FD Interest Posting Reports'
"Posted outside approval".
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The component, service and template for the FD Maturity Reports screen
itself — the previous commit wired up its route, nav entry and the
day-close/product-summary integration, but the new directory was never
staged alongside them.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds the FD Maturity Reports screen (due-without-report, generate/
approve, branch and head-office scope, detail with closure instruction
and estimated interest per deposit), a nav entry, the route, and
Branch Day Closing's maturing-today section and approval-pending
warning banner.
Adds "Matured automatically" to the maturity screen: deposits that
settled via their own Transfer-to-Savings or Reinvest instruction,
needing no approval, listed for visibility with product totals and
per-deposit detail.
Adds "Product summary" to the FD Interest Posting Reports screen
(head office): interest by product and scheme — posted through the
report, still pending, and posted directly at maturity instead — added
up to what each product has paid out in total over a period.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Added 'mybank' to fineractPlatformTenantIds in all three places the tenant
selector reads it from, so the local database + tenant-store registration just
created (fineract_mybank, identifier "mybank", name "MyBank", copied from
lincpay's local connection settings onto a fresh empty schema) shows up as a
login option:
- src/assets/env.js (window['env'] default, read before Angular bootstraps)
- src/environments/environment.ts (dev build fallback)
- src/environments/environment.prod.ts (prod build fallback)
Each already listed utkarshbank, lincpay, utkarshnagari, testbank, humarwork,
default -- this only appends mybank, nothing else in the list changes.
.env.ts is the auto-generated build stamp (npm run env) and picked up
incidentally alongside; it carries no logic.
Not included in this commit: the fd-interest-posting / fd-maturity-report /
branch-day / shell.component.html changes sitting in the working tree are a
separate, unrelated, in-progress feature and are deliberately left out.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Each report line now shows the span its interest covers — "01 Oct to
31 Dec" rather than just the end date — and the report header shows
the product's posting cycle (Monthly, Quarterly, Half-yearly, Yearly).
Adds a "Posted outside approval" view: deposit interest posted without
this report's approval, chiefly a deposit that matured before its own
posting cycle completed. Product-wise totals plus a detail list with
when each posting actually reached the account.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds the FD Interest Posting Reports screen (due-without-report,
generate/approve, branch and head-office scope, posting detail,
live preview, head-office summary), a nav entry under Reports, the
route, and Branch Day Closing's fixed-deposit-due section and
approval-pending warning banner that blocks closing the day.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The product name is unique in the database, so a repeat click on Submit
while the first request is still in flight fails with a duplicate key
error even though the first request already created the product. Disables
the button and ignores repeat calls until the request settles; also drops
a stray debug console.log from the submit payload.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Removes the Pending Share Accounts section that had been bolted onto the
Pending Account screen (duplicate data/actions alongside the normal-account
table), restoring it as its own standalone queue. The standalone
pending-share-accounts route/component already existed but had no tab link
anywhere in the Approval Center nav, so it was unreachable from the UI -
added a "Pending Share Accounts" tab for 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>
- Reports > Interest Posting Reports: per branch and product, generate/regenerate
at any time, approve; branch column, HO-on-behalf marker, posted txn per account
- Reports > Interest Posting Summary (branch-wise) for the head office, with Excel export
- Day Close warns and disables Close Day while the branch's interest report is unapproved
- Savings product accounting: Interest On Savings (expense), Savings Interest Payable
and Paid (liability rows, required)
- RBI Form 1 statutory and Form 9 return screens, reserve config updates
- Interest posting report GETs exempted from the response cache
Co-Authored-By: Claude Opus 5.5 (1M context) <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>