WEB-296: add undo write-off in the upper right menu

This commit is contained in:
Attila Budai
2025-09-16 10:41:19 +02:00
committed by Aleksandar Vidakovic
parent 6a1a8a660a
commit 622a738caa
8 changed files with 183 additions and 3 deletions
@@ -79,6 +79,8 @@ export class LoanActionButtonResolver {
return this.loansService.getLoanActionTemplate(loanId, 'contractTermination');
} else if (loanActionButton === 'Buy Down Fee') {
return this.loansService.getLoanActionTemplate(loanId, 'buyDownFee');
} else if (loanActionButton === 'Undo Write-off') {
return undefined;
} else {
return undefined;
}
@@ -66,3 +66,4 @@
[dataObject]="navigationData"
*ngIf="actions['Add Interest Pause']"
></mifosx-add-interest-pause>
<mifosx-undo-write-off [dataObject]="actionButtonData" *ngIf="actions['Undo Write-off']"></mifosx-undo-write-off>
@@ -30,6 +30,7 @@ import { AssetTransferLoanComponent } from './asset-transfer-loan/asset-transfer
import { LoanReagingComponent } from './loan-reaging/loan-reaging.component';
import { LoanReamortizeComponent } from './loan-reamortize/loan-reamortize.component';
import { AddInterestPauseComponent } from './add-interest-pause/add-interest-pause.component';
import { UndoWriteOffComponent } from './undo-write-off/undo-write-off.component';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/**
@@ -69,7 +70,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
AssetTransferLoanComponent,
LoanReagingComponent,
LoanReamortizeComponent,
AddInterestPauseComponent
AddInterestPauseComponent,
UndoWriteOffComponent
]
})
export class LoanAccountActionsComponent {
@@ -116,6 +118,7 @@ export class LoanAccountActionsComponent {
'Capitalized Income': boolean;
'Contract Termination': boolean;
'Buy Down Fee': boolean;
'Undo Write-off': boolean;
} = {
Close: false,
'Undo Approval': false,
@@ -154,7 +157,8 @@ export class LoanAccountActionsComponent {
'Add Interest Pause': false,
'Capitalized Income': false,
'Contract Termination': false,
'Buy Down Fee': false
'Buy Down Fee': false,
'Undo Write-off': false
};
actionButtonData: any;
@@ -0,0 +1,32 @@
<div class="container mat-elevation-z8">
<mat-card>
<form [formGroup]="undoWriteOffLoanForm" (ngSubmit)="submit()">
<mat-card-content>
<div class="layout-column">
<p class="m-b-20">
{{ 'labels.text.Undo Write-off Description' | translate }}
</p>
<mat-form-field>
<mat-label>{{ 'labels.inputs.Note' | translate }}</mat-label>
<textarea matInput formControlName="note" cdkTextareaAutosize cdkAutosizeMinRows="2"></textarea>
</mat-form-field>
</div>
<mat-card-actions class="layout-row align-center gap-5px responsive-column">
<button type="button" mat-raised-button [routerLink]="['../../general']">
{{ 'labels.buttons.Cancel' | translate }}
</button>
<button
mat-raised-button
color="primary"
[disabled]="!undoWriteOffLoanForm.valid"
*mifosxHasPermission="'UNDOWRITEOFF_LOAN'"
>
{{ 'labels.buttons.Submit' | translate }}
</button>
</mat-card-actions>
</mat-card-content>
</form>
</mat-card>
</div>
@@ -0,0 +1,32 @@
.container {
max-width: 37rem;
}
.mat-card {
padding: 20px;
}
.layout-column {
display: flex;
flex-direction: column;
gap: 20px;
}
.mat-card-actions {
padding-top: 20px;
}
.gap-5px {
gap: 5px;
}
.responsive-column {
@media (width <= 768px) {
flex-direction: column;
align-items: stretch;
}
}
.m-b-20 {
margin-bottom: 20px;
}
@@ -0,0 +1,102 @@
/** Angular Imports */
import { Component, OnInit, Input } from '@angular/core';
import { UntypedFormGroup, UntypedFormBuilder, Validators, ReactiveFormsModule } from '@angular/forms';
import { ActivatedRoute, Router } from '@angular/router';
/** Custom Services */
import { LoansService } from 'app/loans/loans.service';
import { SettingsService } from 'app/settings/settings.service';
import { AlertService } from 'app/core/alert/alert.service';
import { Dates } from 'app/core/utils/dates';
import { CdkTextareaAutosize } from '@angular/cdk/text-field';
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
/**
* Loan Undo Write-off Action
*/
@Component({
selector: 'mifosx-undo-write-off',
templateUrl: './undo-write-off.component.html',
styleUrls: ['./undo-write-off.component.scss'],
imports: [
...STANDALONE_SHARED_IMPORTS,
CdkTextareaAutosize
]
})
export class UndoWriteOffComponent implements OnInit {
@Input() dataObject: any;
/** Loan Id */
loanId: string;
/** Minimum Date allowed. */
minDate = new Date(2000, 0, 1);
/** Maximum Date allowed. */
maxDate = new Date();
/** Undo Write-off Loan Form */
undoWriteOffLoanForm: UntypedFormGroup;
/**
* @param {FormBuilder} formBuilder Form Builder.
* @param {LoansService} loanService Loan Service.
* @param {ActivatedRoute} route Activated Route.
* @param {Router} router Router for navigation.
* @param {SettingsService} settingsService Settings Service
*/
constructor(
private formBuilder: UntypedFormBuilder,
private loanService: LoansService,
private route: ActivatedRoute,
private router: Router,
private dateUtils: Dates,
private settingsService: SettingsService,
private alertService: AlertService
) {
this.loanId = this.route.snapshot.params['loanId'];
}
/**
* Creates the undo write-off loan form
* and initialize with the required values
*/
ngOnInit() {
this.maxDate = this.settingsService.businessDate;
this.createUndoWriteOffLoanForm();
}
/**
* Creates the undo write-off loan form
*/
createUndoWriteOffLoanForm() {
this.undoWriteOffLoanForm = this.formBuilder.group({
note: ['']
});
}
/** Submits the undo write-off form */
submit() {
const undoWriteOffLoanFormData = this.undoWriteOffLoanForm.value;
const locale = this.settingsService.language.code;
const dateFormat = this.settingsService.dateFormat;
const operationDate = this.settingsService.businessDate;
const data = {
...undoWriteOffLoanFormData,
transactionDate: this.dateUtils.formatDate(operationDate && new Date(operationDate), dateFormat),
transactionAmount: 0,
dateFormat,
locale
};
this.loanService.submitLoanActionButton(this.loanId, data, 'undowriteoff').subscribe({
next: (response: any) => {
this.router.navigate(['../../general'], { relativeTo: this.route });
},
error: (error) => {
console.error('Undo write-off failed:', error);
this.alertService.alert({
type: 'Undo Write-off Failed',
message:
'An error occurred while processing the undo write-off transaction. Please try again or contact support if the problem persists.'
});
}
});
}
}
@@ -124,6 +124,11 @@ export class LoansAccountButtonConfiguration {
name: 'Recovery Payment',
icon: 'briefcase',
taskPermissionName: 'RECOVERYPAYMENT_LOAN'
},
{
name: 'Undo Write-off',
icon: 'undo',
taskPermissionName: 'UNDOWRITEOFF_LOAN'
}
];
break;
+3 -1
View File
@@ -2616,6 +2616,7 @@
"Recover From Guarantor": "Recover From Guarantor",
"Recovery Payment": "Recovery Payment",
"Reject": "Reject",
"Undo Write-off": "Undo Write-off",
"Reports": "Reports",
"Reschedule": "Reschedule",
"Savings": "Savings",
@@ -3428,7 +3429,8 @@
"Voluntary": "Voluntary",
"Write a note": "Write a note",
"“Maker-Checker” principle requires every tasks": "The “Maker-Checker” principle requires every tasks to be completed by two people to reduce the chance of errors and misuse. One person initiates the process and the second completes it.",
"Buy Down Fees": "Buy Down Fees"
"Buy Down Fees": "Buy Down Fees",
"Undo Write-off Description": "This action will reverse the write-off transaction and restore the loan to its previous active status. Please provide a note explaining the reason for this action."
},
"titles": {
"Dashboard": "Dashboard",