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]

Reply via email to