Aman-Mittal opened a new pull request, #847:
URL: https://github.com/apache/fineract-backoffice-ui/pull/847

   Four things, in five commits. The module's API surface was already fully 
reached by numeric id, so none of this is a wrapper for its own sake — each 
piece is a capability that had no way in.
   
   ## 1. The book at portfolio level
   
   Every working-capital screen was one loan or one piece of reference data; 
nothing said what the book looks like. The overview reports outstanding, 
delinquency and its aging, the status mix, and the flags the platform sets, 
with a link through to the loans list.
   
   **It states figures Fineract states per loan and adds them up.** Nothing is 
inferred beyond addition and banding day counts. In particular it does **not** 
claim which loans are "in breach": `breach` is the definition attached to the 
loan, `breachStartDate` is a date this project has never had to pin down, and 
every existing screen reads breach as per-loan *actions* instead. A derived 
breach flag would put a risk judgement the module does not make onto a screen 
that reads as authoritative. The one breach figure the platform names, 
`balance.breachPastDueAmount`, is reported under that name.
   
   The arithmetic is a pure `summarisePortfolio` in the adapter port, not a 
template expression, because these totals are the screen's whole claim. The 
aging bands are tested at every boundary, and the band totals are asserted to 
**sum back to the portfolio total** — the one thing a reader checks.
   
   New code cannot import the generated client (ADR 0006), so this comes with a 
narrow port: two reads, a snapshot model whose numbers are non-optional, and a 
mapper that resolves every absent figure to zero. The generated type marks all 
80-odd fields optional; one `undefined` in a column of money renders as `NaN`, 
so absence is decided once in a tested mapper rather than at each `+`.
   
   ## 2. Charts for the aging bands and the status mix
   
   The aging bands are an **ordinal** ramp — one blue hue, light to dark — so 
"older" reads as "darker" without asking anyone to learn five hues. The 
statuses are **categorical** and take the fixed slot order; a sixth status is 
not a sixth hue, it folds into one deliberately neutral "Other", so a slice 
keeps its colour as long as it keeps its rank.
   
   Both charts plot loan **counts**. The amounts stay in the tables: charting 
one of them here would put two scales in one picture.
   
   Every step was validated against its own surface — ordinal mode for the ramp 
(monotone lightness, visible step gaps, light end clearing the surface) and 
categorical mode for the statuses (lightness band, chroma floor, colour-vision 
separation). Dark steps are **selected** per theme rather than flipped, which 
`ThemeService.isDarkMode` already makes possible. The light categorical steps 
sit below 3:1 on the light surface, which obliges a non-colour reading of the 
same data: hence a table under each chart and a label on every slice.
   
   Worth raising separately: **the palette the dashboard's existing donuts use 
does not pass** — one of its four steps falls below the chroma floor and reads 
as grey, and three fall under 3:1. It is deliberately not extended here and is 
left for its own change rather than quietly reused.
   
   No charting dependency: this reuses the app-owned SVG chart components, and 
the screen uses plain semantic markup rather than Ionic cards, because ADR 0005 
closes the vendor boundary to new files and `app/ui` has no card primitive — 
the gap #684 describes.
   
   ## 3. Opening a loan by its external id
   
   Fineract addresses every working-capital resource twice, by its own numeric 
id and by the external id the institution set, and this application only ever 
used the numeric half. An operator holding their own reference had to scroll 
the list.
   
   A lookup on the loans list resolves the reference through `GET 
/working-capital-loans/external-id/{loanExternalId}` and hands over to the 
ordinary loan view, replacing the URL so the back button returns where the 
operator came from. `/working-capital/loans/external/<ref>` is then a shareable 
address for a loan nobody has the numeric id for. The route is declared ahead 
of every `loans/:id/...` pattern so an external id is never read as a numeric 
one.
   
   A reference matching nothing answers `null`, not an error — that is the 
lookup working, and the screen names the reference back. A real failure keeps 
its own path with a retry, because "no such loan" and "the server broke" are 
different answers.
   
   ## 4. The internal commands, behind developer tools
   
   The three `/v1/internal/**` working-capital commands — activate a loan, 
regenerate its amortization schedule, step it into the next delinquency period 
— had no way in.
   
   They are **not** offered as product operations. Fineract serves 
`/v1/internal/**` only under its `test` Spring profile, which upstream says 
must not be enabled in production, so on any other deployment they answer 404. 
The route is matched only where `developerToolsEnabled` is set, the nav entry 
is a `developerTool`, and the screen states the constraint before offering 
anything. They live in their own port so a product contract cannot grow a 
dependency on a test-only endpoint by accident, and 
`check-internal-endpoints.mjs` has one file to pin rather than a screen each.
   
   **This is the one part I could not exercise end to end.** The optional date 
parameters are left to the platform's default rather than guessed, the success 
message says the platform *accepted* the command rather than claiming an 
outcome, and the tests pin the shape rather than the behaviour of a live 
instance. Worth a look from anyone with a test-profile instance.
   
   ## Tests
   
   56 unit tests across the port arithmetic, the mapper, both screens and the 
lookup, plus a mocked e2e covering the overview's totals and the not-found 
reference. Written as invariants where possible: the band totals must sum to 
the portfolio total, and a mapper that let an `undefined` through would fail on 
the `NaN` assertion.
   
   ## Checks
   
   - unit suite 326 files / 2803 tests; `lint` silent with 
`eslint-suppressions.json` unchanged; `tsc` app + e2e clean
   - `i18n:check` consistent with `fr` at 100% and `hi` carrying all 30 new 
keys; `format:check` clean
   - `api:surface` records the four newly used operations (644 → 648); 
`ga:check` 10/11 with 0 blocking
   - `check:internal-endpoints`, `check:nav-ids`, `check:route-permissions`, 
`check:a11y-names`, `check:template-text`, `check:ui-primitives`, 
`check:responsive`, `check:theme-contrast`, `check:icons` all pass
   - mocked e2e 2/2
   


-- 
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]

Reply via email to