Skip to content

WEB-657: WorkingCapital Loan disbursement#3447

Merged
alberto-art3ch merged 1 commit into
openMF:devfrom
alberto-art3ch:WEB-657/workingcapital-loan-disbursement
Mar 27, 2026
Merged

WEB-657: WorkingCapital Loan disbursement#3447
alberto-art3ch merged 1 commit into
openMF:devfrom
alberto-art3ch:WEB-657/workingcapital-loan-disbursement

Conversation

@alberto-art3ch
Copy link
Copy Markdown
Collaborator

@alberto-art3ch alberto-art3ch commented Mar 27, 2026

Description

Now that we have the WorkingCapital Loan account creation we need to disburse the account once time that It has being approved

WEB-657

Screenshots

Screenshot 2026-03-26 at 6 00 42 PM

Checklist

Please make sure these boxes are checked before submitting your pull request - thanks!

  • If you have multiple commits please combine them into one commit by squashing them.

  • Read and understood the contribution guidelines at web-app/.github/CONTRIBUTING.md.

Summary by CodeRabbit

  • New Features

    • Added a Discount field for Working Capital on disbursement and approval forms.
    • Unified input-amount layout so currency display/field rendering is consistent.
  • Bug Fixes

    • Prevented multiple concurrent submissions while a disbursement is processing.
    • Fixed undo-disbursal to correctly handle Working Capital flows and surface submission errors on the form.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 27, 2026

Note

.coderabbit.yaml has unrecognized properties

CodeRabbit is using all valid settings from your configuration. Unrecognized properties (listed below) have been ignored and may indicate typos or deprecated fields that can be removed.

⚠️ Parsing warnings (1)
Validation error: Unrecognized key(s) in object: 'pre_merge_checks'
⚙️ Configuration instructions
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Walkthrough

Adds Working Capital support across loan actions: conditional discount input controls, dynamic form controls, submission-state gating, payload restructuring (nested paymentDetails), and conditional routing to either standard loanActionButtons or applyWorkingCapitalLoanAccountCommand service calls.

Changes

Cohort / File(s) Summary
Disburse Component
src/app/loans/loans-view/loan-account-actions/disburse/disburse.component.html, src/app/loans/loans-view/loan-account-actions/disburse/disburse.component.ts
Template: render discountAmount input when isWorkingCapital. TS: add isSubmitting flag, add discountAmount control when needed, coerce transactionAmount to number, build nested paymentDetails for working-capital flows, and send transformed payload to appropriate service call.
Approve Loan Component
src/app/loans/loans-view/loan-account-actions/approve-loan/approve-loan.component.html, src/app/loans/loans-view/loan-account-actions/approve-loan/approve-loan.component.ts
Template/TS: add conditional discountAmount form control and input when isWorkingCapital, so approve payload includes discount for working-capital flows.
Undo-Disbursal Component
src/app/loans/loans-view/loan-account-actions/undo-disbursal/undo-disbursal.component.ts
Selects loanCommand and conditionally routes request to loanActionButtons() or applyWorkingCapitalLoanAccountCommand() based on product type; subscription handling split into next/error handlers and sets form-level submit errors on failure.
Shared Input Amount
src/app/shared/input-amount/input-amount.component.html
Unifies DOM structure between required/non-required branches: adds input-container class and input-group wrapper to non-required branch to match required branch (DOM/styling alignment).

Sequence Diagram(s)

sequenceDiagram
    participant User as User
    participant UI as DisburseComponent
    participant Service as LoanService
    participant Backend as Backend

    User->>UI: Submit disbursement form
    UI->>UI: Validate form & set isSubmitting = true
    alt isWorkingCapital
        UI->>UI: Add discountAmount (if present) & nest paymentDetails
        UI->>Service: applyWorkingCapitalLoanAccountCommand(payload)
    else
        UI->>Service: loanActionButtons(loanId, 'disburse', payload)
    end
    Service->>Backend: POST request
    alt Success
        Backend-->>Service: 200 OK
        Service-->>UI: Success
        UI->>UI: Navigate to loan view
    else Error
        Backend-->>Service: Error
        Service-->>UI: Error
        UI->>UI: set isSubmitting = false, mark form submitFailed
    end
Loading
sequenceDiagram
    participant User as User
    participant UI as UndoDisbursalComponent
    participant Service as LoanService
    participant Backend as Backend

    User->>UI: Submit undo-disbursal
    UI->>UI: Compute loanCommand (undodisbursal / undolastdisbursal)
    alt isLoanProduct
        UI->>Service: loanActionButtons(loanId, command, {note})
    else isWorkingCapital
        UI->>Service: applyWorkingCapitalLoanAccountCommand(command, {note})
    else Neither
        UI->>UI: return (no request)
    end
    Service->>Backend: POST request
    alt Success
        Backend-->>Service: 200 OK
        Service-->>UI: Success
        UI->>UI: Navigate to loan view
    else Error
        Backend-->>Service: Error
        Service-->>UI: Error
        UI->>UI: mark form submitFailed
    end
Loading

Estimated Code Review Effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly Related PRs

Suggested Reviewers

  • adamsaghy
🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main objective of the PR: adding WorkingCapital Loan disbursement functionality, which aligns with the substantial changes across disburse, approve-loan, and undo-disbursal components.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (2)
src/app/loans/loans-view/loan-account-actions/disburse/disburse.component.ts (1)

140-140: Consider using explicit number conversion.

Using * 1 for number coercion is unconventional and less readable. Prefer Number() or unary + for clarity.

♻️ Proposed fix
-    payload['transactionAmount'] = payload['transactionAmount'] * 1;
+    payload['transactionAmount'] = Number(payload['transactionAmount']);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/loans/loans-view/loan-account-actions/disburse/disburse.component.ts`
at line 140, Replace the unconventional numeric coercion
payload['transactionAmount'] = payload['transactionAmount'] * 1 with an explicit
conversion such as payload['transactionAmount'] =
Number(payload['transactionAmount']) (or payload['transactionAmount'] =
+payload['transactionAmount']) in disburse.component.ts; update the assignment
where payload.transactionAmount is prepared (the transactionAmount conversion
step) to use Number(...) for clarity and maintainability.
src/app/loans/loans-view/loan-account-actions/undo-disbursal/undo-disbursal.component.ts (1)

53-71: Consider adding submission guard for consistency.

The disburse.component.ts implements an isSubmitting flag to prevent duplicate submissions, but this component lacks the same protection. Rapid clicks on the submit button could trigger multiple undo-disbursal requests.

♻️ Proposed refactor to add submission guard

Add an isSubmitting field to the component:

+  isSubmitting = false;
+
   submit() {
     let loanCommand = 'undodisbursal';
     if (this.actionName === 'Undo Last Disbursal') {
       loanCommand = 'undolastdisbursal';
     }
     const request$ = this.isLoanProduct
       ? this.loanService.loanActionButtons(this.loanId, loanCommand, { note: this.note.value })
       : this.isWorkingCapital
         ? this.loanService.applyWorkingCapitalLoanAccountCommand(this.loanId, loanCommand, { note: this.note.value })
         : undefined;

     if (!request$) {
       return;
     }

+    this.isSubmitting = true;
     request$.subscribe({
       next: () => this.gotoLoanDefaultView(),
-      error: () => {}
+      error: () => {
+        this.note.setErrors({ submitFailed: true });
+        this.isSubmitting = false;
+      }
     });
   }

Then update the template's submit button to disable when isSubmitting is true.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/loans/loans-view/loan-account-actions/undo-disbursal/undo-disbursal.component.ts`
around lines 53 - 71, The submit() handler in undo-disbursal.component.ts lacks
a submission guard, allowing duplicate requests on rapid clicks; add an
isSubmitting boolean field to the component, set isSubmitting = true before
calling the service and set it back to false in both the next and error handlers
of request$.subscribe (or use finalize) to prevent multiple submissions, and
update the template's submit button to disable when isSubmitting is true;
reference submit(), request$, and loanCommand to locate where to set the guard.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/app/loans/loans-view/loan-account-actions/disburse/disburse.component.html`:
- Around line 49-56: Replace the hardcoded label string in the template: inside
the mifosx-input-amount for the discount field (the element bound to
disbursementLoanForm.controls.discountAmount and rendered when
isWorkingCapital), change inputLabel from the literal 'Discount' to an i18n
translation key (e.g. use the translate pipe or the component's translated
variable such as "loans.disburse.discount" via translate.instant or |
translate). Add that key to the translation source files and run npm run
translations:extract to extract/update the i18n entries.

In
`@src/app/loans/loans-view/loan-account-actions/disburse/disburse.component.ts`:
- Around line 141-158: The code unconditionally builds paymentDetails inside the
isWorkingCapital branch, which can include undefined fields when payment
controls are hidden; update the logic in the DisburseComponent method where
this.isWorkingCapital is handled so that you only construct and attach
payload['paymentDetails'] when payment details are shown (e.g. check
this.showPaymentDetails or the payment form group/control existence) or, if you
must build it, filter out keys with undefined values before assigning to
payload; ensure you still remove the original flat keys (paymentTypeId,
accountNumber, checkNumber, routingCode, receiptNumber, bankNumber) only when
paymentDetails was actually set to avoid sending an object with undefined
properties.

In
`@src/app/loans/loans-view/loan-account-actions/undo-disbursal/undo-disbursal.component.ts`:
- Around line 68-71: The subscription in undo-disbursal.component.ts currently
swallows errors (request$.subscribe(... error: () => {})) so the user gets no
feedback on failure; replace the empty error handler with one that surfaces the
failure (e.g., set form/group errors or call the same error-handling used in
disburse.component.ts), pass the received error into this.form.setErrors({
undoDisbursal: error }) or invoke the shared notification/toast service, and
ensure the template can display the form error so the user sees the failure
instead of a silent no-op; keep the existing next handler
(this.gotoLoanDefaultView()) unchanged.

---

Nitpick comments:
In
`@src/app/loans/loans-view/loan-account-actions/disburse/disburse.component.ts`:
- Line 140: Replace the unconventional numeric coercion
payload['transactionAmount'] = payload['transactionAmount'] * 1 with an explicit
conversion such as payload['transactionAmount'] =
Number(payload['transactionAmount']) (or payload['transactionAmount'] =
+payload['transactionAmount']) in disburse.component.ts; update the assignment
where payload.transactionAmount is prepared (the transactionAmount conversion
step) to use Number(...) for clarity and maintainability.

In
`@src/app/loans/loans-view/loan-account-actions/undo-disbursal/undo-disbursal.component.ts`:
- Around line 53-71: The submit() handler in undo-disbursal.component.ts lacks a
submission guard, allowing duplicate requests on rapid clicks; add an
isSubmitting boolean field to the component, set isSubmitting = true before
calling the service and set it back to false in both the next and error handlers
of request$.subscribe (or use finalize) to prevent multiple submissions, and
update the template's submit button to disable when isSubmitting is true;
reference submit(), request$, and loanCommand to locate where to set the guard.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a4e311ab-57b9-41f3-a3bf-ef606b283466

📥 Commits

Reviewing files that changed from the base of the PR and between f82ad09 and bf26442.

📒 Files selected for processing (3)
  • src/app/loans/loans-view/loan-account-actions/disburse/disburse.component.html
  • src/app/loans/loans-view/loan-account-actions/disburse/disburse.component.ts
  • src/app/loans/loans-view/loan-account-actions/undo-disbursal/undo-disbursal.component.ts

Comment on lines +49 to +56
@if (isWorkingCapital) {
<mifosx-input-amount
[currency]="currency"
[inputFormControl]="disbursementLoanForm.controls.discountAmount"
[inputLabel]="'Discount'"
>
</mifosx-input-amount>
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Use i18n translation for the "Discount" label.

The inputLabel uses a hardcoded string 'Discount' instead of an i18n variable. As per coding guidelines, all user-facing strings should use proper i18n variables from @ngx-translate/core.

🌐 Proposed fix
           `@if` (isWorkingCapital) {
             <mifosx-input-amount
               [currency]="currency"
               [inputFormControl]="disbursementLoanForm.controls.discountAmount"
-              [inputLabel]="'Discount'"
+              [inputLabel]="'labels.inputs.Discount' | translate"
             >
             </mifosx-input-amount>
           }

Also run npm run translations:extract to extract the new i18n variable.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
@if (isWorkingCapital) {
<mifosx-input-amount
[currency]="currency"
[inputFormControl]="disbursementLoanForm.controls.discountAmount"
[inputLabel]="'Discount'"
>
</mifosx-input-amount>
}
`@if` (isWorkingCapital) {
<mifosx-input-amount
[currency]="currency"
[inputFormControl]="disbursementLoanForm.controls.discountAmount"
[inputLabel]="'labels.inputs.Discount' | translate"
>
</mifosx-input-amount>
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/loans/loans-view/loan-account-actions/disburse/disburse.component.html`
around lines 49 - 56, Replace the hardcoded label string in the template: inside
the mifosx-input-amount for the discount field (the element bound to
disbursementLoanForm.controls.discountAmount and rendered when
isWorkingCapital), change inputLabel from the literal 'Discount' to an i18n
translation key (e.g. use the translate pipe or the component's translated
variable such as "loans.disburse.discount" via translate.instant or |
translate). Add that key to the translation source files and run npm run
translations:extract to extract/update the i18n entries.

@alberto-art3ch alberto-art3ch force-pushed the WEB-657/workingcapital-loan-disbursement branch from bf26442 to 93556db Compare March 27, 2026 00:46
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/app/loans/loans-view/loan-account-actions/approve-loan/approve-loan.component.ts (1)

55-55: ⚠️ Potential issue | 🟡 Minor

Remove debug console.log statement.

This debug statement should be removed before merging to avoid cluttering browser console in production.

🧹 Proposed fix
     this.route.data.subscribe((data: { actionButtonData: any }) => {
-      console.log(data.actionButtonData);
       this.loanData = data.actionButtonData;
       this.currency = data.actionButtonData.currency;
     });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/app/loans/loans-view/loan-account-actions/approve-loan/approve-loan.component.ts`
at line 55, In the ApproveLoanComponent (approve-loan.component.ts) remove the
debug console.log call that prints data.actionButtonData; locate the
console.log(data.actionButtonData) inside the component (e.g., in the method
handling incoming data or ngOnInit) and delete that statement so the production
bundle doesn't emit debug logs.
🧹 Nitpick comments (1)
src/app/loans/loans-view/loan-account-actions/disburse/disburse.component.ts (1)

140-140: Consider using explicit number conversion.

Using * 1 for number coercion works but is less readable. Consider using Number() or the unary + operator for clarity.

✨ Optional style improvement
-    payload['transactionAmount'] = payload['transactionAmount'] * 1;
+    payload['transactionAmount'] = Number(payload['transactionAmount']);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/loans/loans-view/loan-account-actions/disburse/disburse.component.ts`
at line 140, Replace the implicit numeric coercion using multiplication by 1
with an explicit conversion for clarity: in the disburse component where
payload['transactionAmount'] is set (the line using payload['transactionAmount']
= payload['transactionAmount'] * 1), change it to use
Number(payload['transactionAmount']) or the unary + (e.g.,
+payload['transactionAmount']) so the intent to convert to a number is explicit;
ensure you update any surrounding validation if you need to handle NaN cases
after conversion.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In
`@src/app/loans/loans-view/loan-account-actions/approve-loan/approve-loan.component.ts`:
- Line 55: In the ApproveLoanComponent (approve-loan.component.ts) remove the
debug console.log call that prints data.actionButtonData; locate the
console.log(data.actionButtonData) inside the component (e.g., in the method
handling incoming data or ngOnInit) and delete that statement so the production
bundle doesn't emit debug logs.

---

Nitpick comments:
In
`@src/app/loans/loans-view/loan-account-actions/disburse/disburse.component.ts`:
- Line 140: Replace the implicit numeric coercion using multiplication by 1 with
an explicit conversion for clarity: in the disburse component where
payload['transactionAmount'] is set (the line using payload['transactionAmount']
= payload['transactionAmount'] * 1), change it to use
Number(payload['transactionAmount']) or the unary + (e.g.,
+payload['transactionAmount']) so the intent to convert to a number is explicit;
ensure you update any surrounding validation if you need to handle NaN cases
after conversion.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 8157a94b-cfe8-439b-8972-45d6e3e2fd29

📥 Commits

Reviewing files that changed from the base of the PR and between bf26442 and 93556db.

📒 Files selected for processing (6)
  • src/app/loans/loans-view/loan-account-actions/approve-loan/approve-loan.component.html
  • src/app/loans/loans-view/loan-account-actions/approve-loan/approve-loan.component.ts
  • src/app/loans/loans-view/loan-account-actions/disburse/disburse.component.html
  • src/app/loans/loans-view/loan-account-actions/disburse/disburse.component.ts
  • src/app/loans/loans-view/loan-account-actions/undo-disbursal/undo-disbursal.component.ts
  • src/app/shared/input-amount/input-amount.component.html
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/app/loans/loans-view/loan-account-actions/undo-disbursal/undo-disbursal.component.ts

Copy link
Copy Markdown
Collaborator

@adamsaghy adamsaghy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants