Aman-Mittal opened a new pull request, #342:
URL: https://github.com/apache/fineract-backoffice-ui/pull/342
## What and why
Finishes the product accounting epic #288. Two remaining families of mapping
had nowhere to be configured.
Closes #293. Closes #294.
## Share products
`share-product-form` pinned `accountingRule: 1` on both create **and** load,
so every share product this application made was unaccounted, and opening an
accounted one and saving it reset it. Share capital is the members' stake in
the institution — the balance-sheet line that cannot be reconstructed
afterwards.
Enumerated from the platform, cash accounting needs **four** slots, not the
three the equity story suggests:
```
POST /products/share {"accountingRule": 2, …no mapping ids…}
→ shareReferenceId (ASSET), shareSuspenseId (LIABILITY),
incomeFromFeeAccountId (INCOME), shareEquityId (EQUITY)
```
`shareEquityId` is the only **equity** slot in the application. Three things
about share products differ from every other family, and are handled rather
than assumed:
- **The template carries no `accountingRuleOptions`.** It is the one product
template that omits them, so the rule selector's options are supplied by the
form.
- **Only `None` and `Cash` are offered.** The validator accepts 1, 2 and 3 —
a 4 is refused with `must be between 1 and 3` — but a product created under
rule 3 asks for no mappings and reads back with `accountingMappings: {}`. That
is a product labelled *ACCRUAL PERIODIC* which posts nothing, which is worse
than one labelled *NONE*, because it looks configured.
- **The response uses the same keys as the request**, `Id` suffix and all.
Every other family drops the suffix on the way out (`fundSourceAccountId` in,
`fundSourceAccount` out).
Also worth knowing: Fineract **omits an option list entirely** when the
tenant holds no accounts of that class — a chart with no equity account returns
no `equityAccountOptions` at all rather than an empty array. That is what the
section's empty-state note is for, and why the e2e creates the equity account
through the chart of accounts first.
## Advanced mappings on loan and savings products
Payment channel → fund source, fee → income, penalty → income. Without them
every collection lands in one fund source and every fee in one income account,
so a till cannot be reconciled at close of day and a processing fee cannot be
told apart from an insurance fee after the fact.
**The platform validates almost nothing here.** Verified accepted, silently,
against a live instance:
| Accepted | Fires |
|---|---|
| a fee mapping naming a charge the product does not carry | never |
| a fee mapping naming a charge whose `penalty` flag is the other way round
| never |
| two rows naming the same payment type | not reliably |
Silent acceptance is worse than rejection: the product looks configured and
is not. So the options are narrowed to what can actually work — charges come
from the product's own list rather than the tenant's catalogue, the two tables
read opposite sides of the `penalty` flag, and a payment type already routed is
not offered again.
This corrects the assumption in #294 that unattached charges "produce
mappings the platform will reject". It does not reject them.
**Request and response disagree about every key**, as with the base slots:
written `{paymentTypeId, fundSourceAccountId}` and `{chargeId,
incomeAccountId}`, read back `{paymentType: {id}, fundSourceAccount: {id}}` and
`{charge: {id}, incomeAccount: {id}}`. A form feeding the response straight
back would show empty selects on a configured product and blank it on the next
save.
**Empty tables send no key.** Both spellings are in fact accepted — a loan
product posts identically with `[]` and with the key absent, contrary to what
#294 anticipated — but omitting matches how the base slots are built.
One scope note: these forms have no charge picker, so a product created here
carries no charges and the two charge tables correctly report there is nothing
to map yet. They come into their own on edit. A charges step on the product
forms is a separate gap.
## Change detection
The rows render from computed view models rather than from methods the
template calls. A method returning a fresh array hands back a new identity on
every change-detection pass, which the dev-mode exhaustive `checkNoChanges`
pass reports as NG0100 and the e2e fixtures fail the run on.
Unrelated but visible in the e2e logs: `GlAccountSelectComponent` emits an
NG0100 for `ng-untouched` on the product **edit** pages, from Angular's own
`NgControlStatus` host binding. Pre-existing, currently a warning rather than a
failure, and not addressed here.
## Verification
- Two real-backend suites: a share product mapped to equity and
round-tripped through edit (new), and the loan product suite extended with a
payment-channel override.
- Unit: 925 pass (16 new) — the share slots and rule set, both payload
directions, and the option-narrowing rules.
- Mocked e2e: 243 pass. Four client-CRUD tests failed only under two local
workers and pass when that file runs alone; they are untouched by this change.
- `npm run lint`, `format:check`, `check:icons`, `i18n:check`, `build` all
clean.
## Checklist
- [x] I did not hand-edit generated files under `src/app/api/`.
- [x] New component uses the adapter boundary (`| appTranslate`), per
ADR-0003.
- [x] New strings added to `en.json`; existing ones left alone.
- [x] Commits are signed.
--
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]