Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ <h4 class="mat-h4 flex-98">

@if (loanProductService.isWorkingCapital) {
<mat-form-field class="flex-48">
<mat-label>{{ 'labels.inputs.Total Payment' | translate }}</mat-label>
<mat-label>{{ 'labels.inputs.Total Payment' | translate }} {{ 'labels.inputs.Volume' | translate }}</mat-label>
<input type="number" matInput required formControlName="totalPayment" />
</mat-form-field>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,7 @@ <h3>{{ 'labels.heading.Loan Amounts' | translate }}</h3>
@if (loanDetails.balance) {
<div class="flex-contents">
<span class="flex-50"
>{{ 'labels.inputs.Total Payment' | translate }} {{ 'labels.inputs.Amount' | translate }}:</span
>{{ 'labels.inputs.Total Payment' | translate }} {{ 'labels.inputs.Volume' | translate }}:</span
>
Comment on lines +271 to 272
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Scope “Volume” label to Working Capital loans only.

Line 271 currently shows “Total Payment Volume” for every loan in this view. This should be conditional; non-working-capital loans should keep the amount label.

Proposed fix
-              <span class="flex-50"
-                >{{ 'labels.inputs.Total Payment' | translate }} {{ 'labels.inputs.Volume' | translate }}:</span
-              >
+              <span class="flex-50">
+                {{ 'labels.inputs.Total Payment' | translate }}
+                {{
+                  (loanProductType() === 'labels.catalogs.Working Capital'
+                    ? ('labels.inputs.Volume' | translate)
+                    : ('labels.inputs.Amount' | translate))
+                }}:
+              </span>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/loans/loans-view/general-tab/general-tab.component.html` around lines
271 - 272, The label currently always renders "Total Payment Volume"; update the
template near the span that outputs {{ 'labels.inputs.Total Payment' | translate
}} and {{ 'labels.inputs.Volume' | translate }} so the "Volume" translation is
only included for Working Capital loans; wrap the Volume part in an Angular
conditional (e.g., *ngIf="isWorkingCapital(loan)" or use a ternary in the
binding checking loan.productType/loan.type === 'WORKING_CAPITAL') and keep
non-working-capital loans showing just the amount label. Ensure you reference
the component method/property (isWorkingCapital or loan.productType/loan.type)
that determines working-capital status.

<span class="flex-50">{{
loanDetails.balance.totalPayment | currency: currencyCode : 'symbol-narrow' : '1.2-2'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
matInput
[min]="minDate"
[matDatepicker]="disbursementDatePicker"
required
formControlName="expectedDisbursementDate"
/>
<mat-datepicker-toggle matSuffix [for]="disbursementDatePicker"></mat-datepicker-toggle>
Expand All @@ -50,11 +51,13 @@
>
</mifosx-input-amount>

<!-- Display Available Disbursement Amount with Over Applied if available -->
<mat-form-field>
<mat-label>{{ 'labels.inputs.Available Disbursement Amount (with Over Applied)' | translate }}</mat-label>
<input matInput [value]="loanData.availableDisbursementAmountWithOverApplied | formatNumber" readonly />
</mat-form-field>
@if (isLoanProduct) {
<!-- Display Available Disbursement Amount with Over Applied if available -->
<mat-form-field>
<mat-label>{{ 'labels.inputs.Available Disbursement Amount (with Over Applied)' | translate }}</mat-label>
<input matInput [value]="loanData.availableDisbursementAmountWithOverApplied | formatNumber" readonly />
</mat-form-field>
}

<mat-form-field>
<mat-label>{{ 'labels.inputs.Note' | translate }}</mat-label>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ export class ApproveLoanComponent extends LoanAccountActionsBaseComponent implem
approveLoanForm: UntypedFormGroup;
/** Loan data. */
loanData: any = new Object();
/** Association Data */
associationData: any;
/** Minimum Date allowed. */
minDate = new Date(2000, 0, 1);
currency: Currency;
Expand All @@ -54,6 +52,7 @@ export class ApproveLoanComponent extends LoanAccountActionsBaseComponent implem
constructor() {
super();
this.route.data.subscribe((data: { actionButtonData: any }) => {
console.log(data.actionButtonData);
this.loanData = data.actionButtonData;
this.currency = data.actionButtonData.currency;
});
Expand All @@ -62,12 +61,6 @@ export class ApproveLoanComponent extends LoanAccountActionsBaseComponent implem

ngOnInit() {
this.setApproveLoanForm();
this.loanService.getApproveAssociationsDetails(this.loanId).subscribe((response: any) => {
this.associationData = response;
this.approveLoanForm.patchValue({
expectedDisbursementDate: new Date(response.timeline.expectedDisbursementDate)
});
});

// Get delinquency data for available disbursement amount with over applied
this.loanService.getLoanDelinquencyDataForTemplate(this.loanId).subscribe((delinquencyData: any) => {
Expand All @@ -76,10 +69,6 @@ export class ApproveLoanComponent extends LoanAccountActionsBaseComponent implem
this.loanData.availableDisbursementAmountWithOverApplied =
delinquencyData.availableDisbursementAmountWithOverApplied;
}
// Also check if it's in delinquent object
if (delinquencyData.delinquent) {
this.loanData.delinquent = delinquencyData.delinquent;
}
});
}

Expand All @@ -92,7 +81,10 @@ export class ApproveLoanComponent extends LoanAccountActionsBaseComponent implem
this.settingsService.businessDate,
Validators.required
],
expectedDisbursementDate: [''],
expectedDisbursementDate: [
new Date(this.loanData.expectedDisbursementDate),
Validators.required
],
approvedLoanAmount: [
this.loanData.approvalAmount,
Validators.required
Expand Down Expand Up @@ -121,11 +113,21 @@ export class ApproveLoanComponent extends LoanAccountActionsBaseComponent implem
dateFormat,
locale
};
const loanCommand: string = 'approve';
const request$ = this.isLoanProduct
? this.loanService.loanActionButtons(this.loanId, loanCommand, data)
: this.isWorkingCapital
? this.loanService.applyWorkingCapitalLoanAccountCommand(this.loanId, loanCommand, data)
: undefined;

if (this.isLoanProduct) {
this.loanService.loanActionButtons(this.loanId, 'approve', data).subscribe((response: any) => {
this.gotoLoanDefaultView();
});
if (!request$) {
this.approveLoanForm.setErrors({ unsupportedProductType: true });
return;
}

request$.subscribe({
next: () => this.gotoLoanDefaultView(),
error: () => this.approveLoanForm.setErrors({ submitFailed: true })
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,17 @@ export class RejectLoanComponent extends LoanAccountActionsBaseComponent impleme
dateFormat,
locale
};
const loanCommand: string = 'reject';
if (this.isLoanProduct) {
this.loanService.loanActionButtons(this.loanId, 'reject', data).subscribe((response: any) => {
this.loanService.loanActionButtons(this.loanId, loanCommand, data).subscribe((response: any) => {
this.gotoLoanDefaultView();
});
} else if (this.isWorkingCapital) {
this.loanService
.applyWorkingCapitalLoanAccountCommand(this.loanId, loanCommand, data)
.subscribe((response: any) => {
this.gotoLoanDefaultView();
});
}
Comment on lines +87 to 98
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion | 🟠 Major

Add error handling and consider edge case coverage.

Several concerns with this submission logic:

  1. No error handling: If the API call fails, users receive no feedback and the UI state becomes inconsistent.
  2. Unused response parameter: The response is typed but never used—either remove it or add proper typing per project conventions.
  3. Silent no-op: If neither isLoanProduct nor isWorkingCapital is true, the method silently does nothing.
Proposed fix with error handling
     const loanCommand: string = 'reject';
     if (this.isLoanProduct) {
-      this.loanService.loanActionButtons(this.loanId, loanCommand, data).subscribe((response: any) => {
-        this.gotoLoanDefaultView();
-      });
+      this.loanService.loanActionButtons(this.loanId, loanCommand, data).subscribe({
+        next: () => this.gotoLoanDefaultView(),
+        error: (err) => console.error('Failed to reject loan', err)
+      });
     } else if (this.isWorkingCapital) {
-      this.loanService
-        .applyWorkingCapitalLoanAccountCommand(this.loanId, loanCommand, data)
-        .subscribe((response: any) => {
-          this.gotoLoanDefaultView();
-        });
+      this.loanService
+        .applyWorkingCapitalLoanAccountCommand(this.loanId, loanCommand, data)
+        .subscribe({
+          next: () => this.gotoLoanDefaultView(),
+          error: (err) => console.error('Failed to reject working capital loan', err)
+        });
+    } else {
+      console.warn('Unknown loan product type; reject action not performed');
     }

Consider also showing a user-facing error notification (e.g., via a toast/snackbar service) rather than just logging to console. Based on learnings: avoid Observable<any> and introduce specific types for API responses as a cross-cutting refactor.

🤖 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/reject-loan/reject-loan.component.ts`
around lines 87 - 98, The submission path for reject action lacks error
handling, silently no-ops when neither isLoanProduct nor isWorkingCapital is
true, and uses an unused any-typed response; update the method to: call
loanService.loanActionButtons(...) and
applyWorkingCapitalLoanAccountCommand(...) with subscribe handlers that handle
both next and error (on success call gotoLoanDefaultView(), on error log and
surface a user-facing message via the app's toast/snackbar service), remove or
replace the unused (response: any) with a concrete response type per API
contracts (or omit the param if unused), and add an else branch that logs/alerts
when no product type matches (or disables the action) to avoid silent no-op;
reference the existing symbols loanActionButtons,
applyWorkingCapitalLoanAccountCommand, gotoLoanDefaultView, isLoanProduct, and
isWorkingCapital when making changes.

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,19 @@ export class UndoApprovalComponent extends LoanAccountActionsBaseComponent imple
* Submits undo approval form.
*/
submit() {
this.loanService
.loanActionButtons(this.loanId, 'undoapproval', { note: this.note.value })
.subscribe((response: any) => {
this.gotoLoanDefaultView();
});
const loanCommand: string = 'undoapproval';
if (this.isLoanProduct) {
this.loanService
.loanActionButtons(this.loanId, loanCommand, { note: this.note.value })
.subscribe((response: any) => {
this.gotoLoanDefaultView();
});
} else if (this.isWorkingCapital) {
this.loanService
.applyWorkingCapitalLoanAccountCommand(this.loanId, loanCommand, { note: this.note.value })
.subscribe((response: any) => {
this.gotoLoanDefaultView();
});
}
}
}
1 change: 1 addition & 0 deletions src/app/login/login-form/login-form.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
autocomplete="current-password"
formControlName="password"
[placeholder]="'labels.placeholders.Enter your password' | translate"
(keyup.enter)="onEnter($event)"
/>
<mifosx-m3-icon matIconPrefix name="lock"></mifosx-m3-icon>
@if (loginForm.controls.password.value && !loading) {
Expand Down
4 changes: 4 additions & 0 deletions src/app/login/login-form/login-form.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,8 @@ export class LoginFormComponent implements OnInit {

return '';
}

onEnter(event: any): void {
this.login();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
<ng-container matColumnDef="bucketType">
<th mat-header-cell *matHeaderCellDef mat-sort-header>{{ 'labels.inputs.Type' | translate }}</th>
<td mat-cell *matCellDef="let delinquencyBucket">
{{ bucketTypeLabel(delinquencyBucket.bucketType) | translateKey: 'catalogs' }}
{{ bucketTypeLabel(delinquencyBucket.bucketType.id) | translateKey: 'catalogs' }}
</td>
</ng-container>

Expand All @@ -51,7 +51,7 @@
mat-row
*matRowDef="let row; columns: displayedColumns"
[routerLink]="[row.id]"
[queryParams]="{ bucketType: bucketType(row.bucketType) }"
[queryParams]="{ bucketType: bucketType(row.bucketType.id) }"
class="select-row"
></tr>
</table>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
</div>

<div class="flex-50">
{{ bucketTypeLabel(delinquencyBucketData.bucketType) | translateKey: 'catalogs' }}
{{ bucketTypeLabel(delinquencyBucketData.bucketType.id) | translateKey: 'catalogs' }}
</div>
</div>
<div class="flex-100 layout-row m-b-10">
Expand Down
1 change: 1 addition & 0 deletions src/assets/translations/cs-CS.json
Original file line number Diff line number Diff line change
Expand Up @@ -2718,6 +2718,7 @@
"View Journal Entry": "Zobrazit záznam deníku",
"View Report": "Zobrazit hlášení",
"View Signature": "Zobrazit podpis",
"Volume": "Objem",
"Waived": "Prominutí",
"Website": "webová stránka",
"Wednesday": "středa",
Expand Down
1 change: 1 addition & 0 deletions src/assets/translations/de-DE.json
Original file line number Diff line number Diff line change
Expand Up @@ -2720,6 +2720,7 @@
"View Journal Entry": "Journaleintrag anzeigen",
"View Report": "Zeige Bericht",
"View Signature": "Signatur anzeigen",
"Volume": "Volumen",
"Waived": "Verzichtet",
"Website": "Webseite",
"Wednesday": "Mittwoch",
Expand Down
1 change: 1 addition & 0 deletions src/assets/translations/en-US.json
Original file line number Diff line number Diff line change
Expand Up @@ -2742,6 +2742,7 @@
"View Journal Entry": "View Journal Entry",
"View Report": "View Report",
"View Signature": "View Signature",
"Volume": "Volume",
"Waived": "Waived",
"Website": "Website",
"Wednesday": "Wednesday",
Expand Down
1 change: 1 addition & 0 deletions src/assets/translations/es-CL.json
Original file line number Diff line number Diff line change
Expand Up @@ -2721,6 +2721,7 @@
"View Journal Entry": "Ver entrada de diario",
"View Report": "Ver reporte",
"View Signature": "Ver firma",
"Volume": "Volumen",
"Waived": "Renunciado",
"Website": "Sitio web",
"Wednesday": "Miércoles",
Expand Down
1 change: 1 addition & 0 deletions src/assets/translations/es-MX.json
Original file line number Diff line number Diff line change
Expand Up @@ -2725,6 +2725,7 @@
"View Journal Entry": "Ver entrada de diario",
"View Report": "Ver reporte",
"View Signature": "Ver firma",
"Volume": "Volumen",
"Waived": "Renunciado",
"Website": "Sitio web",
"Wednesday": "Miércoles",
Expand Down
1 change: 1 addition & 0 deletions src/assets/translations/fr-FR.json
Original file line number Diff line number Diff line change
Expand Up @@ -2723,6 +2723,7 @@
"View Journal Entry": "Afficher l'écriture de journal",
"View Report": "Voir le rapport",
"View Signature": "Afficher la signature",
"Volume": "Volume",
"Waived": "Renoncé",
"Website": "Site web",
"Wednesday": "Mercredi",
Expand Down
1 change: 1 addition & 0 deletions src/assets/translations/it-IT.json
Original file line number Diff line number Diff line change
Expand Up @@ -2719,6 +2719,7 @@
"View Journal Entry": "Visualizza la voce del diario",
"View Report": "Visualizza rapporto",
"View Signature": "Visualizza firma",
"Volume": "Volume",
"Waived": "Rinunciato",
"Website": "Sito web",
"Wednesday": "Mercoledì",
Expand Down
1 change: 1 addition & 0 deletions src/assets/translations/ko-KO.json
Original file line number Diff line number Diff line change
Expand Up @@ -2721,6 +2721,7 @@
"View Journal Entry": "분개 항목 보기",
"View Report": "보고서보기",
"View Signature": "서명 보기",
"Volume": "볼륨",
"Waived": "면제",
"Website": "웹사이트",
"Wednesday": "수요일",
Expand Down
1 change: 1 addition & 0 deletions src/assets/translations/lt-LT.json
Original file line number Diff line number Diff line change
Expand Up @@ -2717,6 +2717,7 @@
"View Journal Entry": "Žiūrėti žurnalo įrašą",
"View Report": "Peržiūrėti ataskaitą",
"View Signature": "Žiūrėti parašą",
"Volume": "Tūris",
"Waived": "Atsisakė",
"Website": "Interneto svetainė",
"Wednesday": "trečiadienį",
Expand Down
1 change: 1 addition & 0 deletions src/assets/translations/lv-LV.json
Original file line number Diff line number Diff line change
Expand Up @@ -2720,6 +2720,7 @@
"View Journal Entry": "Skatīt žurnāla ierakstu",
"View Report": "Skatīt pārskatu",
"View Signature": "Skatīt parakstu",
"Volume": "Apjomi",
"Waived": "Atteicās",
"Website": "Tīmekļa vietne",
"Wednesday": "trešdiena",
Expand Down
1 change: 1 addition & 0 deletions src/assets/translations/ne-NE.json
Original file line number Diff line number Diff line change
Expand Up @@ -2717,6 +2717,7 @@
"View Journal Entry": "जर्नल प्रविष्टि हेर्नुहोस्",
"View Report": "रिपोर्ट हेर्नुहोस्",
"View Signature": "हस्ताक्षर हेर्नुहोस्",
"Volume": "भोल्युमेन",
"Waived": "माफ गरियो",
"Website": "वेबसाइट",
"Wednesday": "बुधबार",
Expand Down
1 change: 1 addition & 0 deletions src/assets/translations/pt-PT.json
Original file line number Diff line number Diff line change
Expand Up @@ -2719,6 +2719,7 @@
"View Journal Entry": "Ver lançamento contábil manual",
"View Report": "Ver relatório",
"View Signature": "Ver assinatura",
"Volume": "Volume",
"Waived": "Dispensado",
"Website": "Local na rede Internet",
"Wednesday": "Quarta-feira",
Expand Down
1 change: 1 addition & 0 deletions src/assets/translations/sw-SW.json
Original file line number Diff line number Diff line change
Expand Up @@ -2716,6 +2716,7 @@
"View Journal Entry": "Tazama Ingizo la Jarida",
"View Report": "Tazama Ripoti",
"View Signature": "Tazama Sahihi",
"Volume": "Kiasi",
"Waived": "Imetolewa",
"Website": "Tovuti",
"Wednesday": "Jumatano",
Expand Down
Loading