Aman-Mittal opened a new issue, #284:
URL: https://github.com/apache/fineract-backoffice-ui/issues/284
## Business value
Two platform operations that revise the money on an approved loan have no UI
at all. Both are in the generated client and neither is called anywhere:
```
putLoansLoanIdApprovedAmount(loanId, { amount, locale })
putLoansLoanIdAvailableDisbursementAmount(loanId, { amount, locale })
```
```
grep -rn
"putLoansLoanIdApprovedAmount\|putLoansLoanIdAvailableDisbursementAmount"
src/app --include=*.ts | grep -v '/app/api/'
# no results
```
**Approved amount** is what a credit committee sanctioned. It changes for
ordinary reasons: the committee approves less than was applied for, a valuation
comes back low, a borrower asks for less, a partial disbursement happens and
the remainder is cut. Today the only way to reflect any of that is to cancel
the approval and start again — which loses the approval record, the checker's
sign-off, and the original application date. On a loan that has already been
partly disbursed, it is not possible at all.
**Available disbursement amount** governs how much of a multi-tranche loan
may still be drawn. Without it, a branch cannot close off the undrawn balance
of a facility, and cannot extend a tranche limit without rebuilding the loan.
The platform also keeps a change history (`LoanApprovedAmountHistoryData` —
`oldApprovedAmount`, `newApprovedAmount`, `dateOfChange`), which exists
precisely so a UI can show who changed a sanction and to what. Nothing reads it.
## Why this is not a beginner issue
The endpoints are trivial. The **rules** are not, and getting them wrong
produces a screen that offers actions the platform will refuse in ways the user
cannot predict. This needs someone comfortable reading acceptance criteria and
deciding what to enable when.
## The rules, from the platform's own acceptance tests
`fineract-e2e-tests-runner/src/test/resources/features/LoanUpdateApprovedAmount.feature`
in `apache/fineract` (`develop`) — 11 scenarios. The constraints:
```gherkin
Then Update loan approved amount is forbidden with amount "0" due to min
allowed amount
Then Update loan approved amount is forbidden with amount "1600" due to
exceed applied amount
```
and the interaction with disbursement (UC3):
```gherkin
And Admin successfully disburse the loan on "1 January 2025" with "100" EUR
transaction amount
Then Update loan approved amount with new amount "600" value
When Admin successfully undo disbursal
Then Admin fails to disburse the loan on "1 January 2025" with "700" EUR
transaction amount due to exceed approved amount
When Admin successfully disburse the loan on "01 January 2025" with "600"
EUR transaction amount
```
So the approved amount can be revised **after a partial disbursement**, and
the new figure binds subsequent disbursements. And with over-applied configured
as a percentage (UC4):
```gherkin
Then Loan has availableDisbursementAmountWithOverApplied field with value:
1500
And Admin successfully disburse the loan on "1 January 2025" with "1100" EUR
transaction amount
Then Loan has availableDisbursementAmountWithOverApplied field with value:
400
```
`LoanUpdateAvailableDisbursementAmount.feature` adds 18 more, and the ones
that shape the UI are:
```gherkin
Scenario: Verify update available disbursement amount to zero is forbidden
for not approved loan
Scenario: Verify update available disbursement amount to zero is forbidden
for approved loan
Scenario: Verify update available disbursement amount to zero is allowed for
active loan after partial disbursement for single disb loan
Scenario: Verify available disbursement amount change is forbidden with
lower value for progressive multidisbursal loan that expects tranches
Scenario: Verify available disbursement amount change with greater value
above approved amount for ... that expects tranches
```
Read together: **whether zero is permitted depends on the loan's status and
on whether anything has been disbursed**, and **whether a decrease is permitted
depends on whether the product expects tranches**. A menu item that is simply
always enabled will produce refusals the user cannot anticipate.
## Describing the change
Two dialogs on the loan view, each an amount field plus `locale`, posting to
its endpoint. `src/app/features/clients/client-transfer-dialog.component.ts` is
a recent, close model for a small dialog returning a typed result, and
`loan-view.component.ts` already holds the actions menu and the
`runCommand`-style reload pattern.
Gate the menu items on loan status. The status constants pattern is
`src/app/features/clients/client-servicing.model.ts` — a named `const` object
rather than integer literals in the template. Loans should have the same;
introducing it here is in scope and welcome.
**Do not encode the full rule set in the client.** Gate on what is stable
and knowable — status, and whether the product is multi-disbursement — and let
the platform refuse the rest. The error interceptor already surfaces the
platform's message. Client-side validation that disagrees with the backend is
worse than none, because it blocks operations that would have succeeded.
**Verify each payload against a live backend before writing the dialog.**
`npm run e2e:stack` brings one up. Commands in this API are routinely
asymmetric about `locale` and `dateFormat` — in this repo `acceptTransfer`
refuses the very fields `proposeTransfer` requires — so confirm whether
`locale` is needed, and what happens if `amount` is omitted. A 400 from
Fineract usually names the offending parameter, and its `args` array often
enumerates the accepted values.
**A change-history panel reading `LoanApprovedAmountHistoryData` is a
natural second PR**, not part of this one. Say so if you intend to do it.
## Testing
- **Unit specs** asserting the exact body for each endpoint, and that the
menu items are hidden for statuses where the operation is refused. Assert
bodies with `toEqual`, not `objectContaining` — whether `locale` is present is
precisely what you are pinning down.
- **A mocked e2e** capturing method, URL and body.
`e2e/client-servicing-gaps.spec.ts` has the `Probe` pattern to copy.
- **A backend e2e** (add the filename to `BACKEND_SPECS` in
`playwright.config.ts`) is the one that earns its keep here, because it is the
only test that proves the payload is accepted. Mirror UC3 above — approve,
disburse partially, revise the approved amount, and assert the loan reflects
the new figure. Everything through the UI; no API seeding.
One trap from an earlier backend e2e in this repo: list rows are inert. The
`routerLink` sits on the name cell, so `row.click()` does nothing and the test
sits on the list until it times out. Use
`row.getByRole('link').first().click()`.
## Scope
In scope: the two dialogs, the menu entries with status gating, and their
tests.
Out of scope: the approved-amount change history panel; over-applied
configuration on the product form; anything about tranche editing.
## Getting started
- Loan view: `src/app/features/loans/loan-view.component.ts`
- Endpoints: `src/app/api/api/loans.service.ts`
- Request models: `putLoansApprovedAmountRequest.ts`,
`putLoansAvailableDisbursementAmountRequest.ts` (both are `{ amount?: number;
locale?: string }`)
- Dialog model to copy:
`src/app/features/clients/client-transfer-dialog.component.ts`
- `npm test`, `npm run lint:prune`, `npm run i18n:check` and `npm run build`
must pass.
- `loan-view.component.ts` is large and under active development. Rebase
before opening the PR, and keep the diff tight.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]