Skip to content

Commit ff852dd

Browse files
committed
WEB-296: add undo write-off in the upper right menu
1 parent 893e958 commit ff852dd

File tree

8 files changed

+190
-3
lines changed

8 files changed

+190
-3
lines changed

src/app/loans/common-resolvers/loan-action-button.resolver.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ export class LoanActionButtonResolver {
7979
return this.loansService.getLoanActionTemplate(loanId, 'contractTermination');
8080
} else if (loanActionButton === 'Buy Down Fee') {
8181
return this.loansService.getLoanActionTemplate(loanId, 'buyDownFee');
82+
} else if (loanActionButton === 'Undo Write-off') {
83+
return undefined;
8284
} else {
8385
return undefined;
8486
}

src/app/loans/loans-view/loan-account-actions/loan-account-actions.component.html

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,3 +66,7 @@
6666
[dataObject]="navigationData"
6767
*ngIf="actions['Add Interest Pause']"
6868
></mifosx-add-interest-pause>
69+
<mifosx-undo-write-off
70+
[dataObject]="actionButtonData"
71+
*ngIf="actions['Undo Write-off']"
72+
></mifosx-undo-write-off>

src/app/loans/loans-view/loan-account-actions/loan-account-actions.component.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { AssetTransferLoanComponent } from './asset-transfer-loan/asset-transfer
3030
import { LoanReagingComponent } from './loan-reaging/loan-reaging.component';
3131
import { LoanReamortizeComponent } from './loan-reamortize/loan-reamortize.component';
3232
import { AddInterestPauseComponent } from './add-interest-pause/add-interest-pause.component';
33+
import { UndoWriteOffComponent } from './undo-write-off/undo-write-off.component';
3334
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
3435

3536
/**
@@ -69,7 +70,8 @@ import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
6970
AssetTransferLoanComponent,
7071
LoanReagingComponent,
7172
LoanReamortizeComponent,
72-
AddInterestPauseComponent
73+
AddInterestPauseComponent,
74+
UndoWriteOffComponent
7375
]
7476
})
7577
export class LoanAccountActionsComponent {
@@ -116,6 +118,7 @@ export class LoanAccountActionsComponent {
116118
'Capitalized Income': boolean;
117119
'Contract Termination': boolean;
118120
'Buy Down Fee': boolean;
121+
'Undo Write-off': boolean;
119122
} = {
120123
Close: false,
121124
'Undo Approval': false,
@@ -154,7 +157,8 @@ export class LoanAccountActionsComponent {
154157
'Add Interest Pause': false,
155158
'Capitalized Income': false,
156159
'Contract Termination': false,
157-
'Buy Down Fee': false
160+
'Buy Down Fee': false,
161+
'Undo Write-off': false
158162
};
159163

160164
actionButtonData: any;
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<div class="container mat-elevation-z8">
2+
<mat-card>
3+
<form [formGroup]="undoWriteOffLoanForm" (ngSubmit)="submit()">
4+
<mat-card-content>
5+
<div class="layout-column">
6+
<p class="m-b-20">
7+
{{ 'labels.text.Undo Write-off Description' | translate }}
8+
</p>
9+
10+
<mat-form-field>
11+
<mat-label>{{ 'labels.inputs.Note' | translate }}</mat-label>
12+
<textarea matInput formControlName="note" cdkTextareaAutosize cdkAutosizeMinRows="2"></textarea>
13+
</mat-form-field>
14+
</div>
15+
16+
<mat-card-actions class="layout-row align-center gap-5px responsive-column">
17+
<button type="button" mat-raised-button [routerLink]="['../../general']">
18+
{{ 'labels.buttons.Cancel' | translate }}
19+
</button>
20+
<button
21+
mat-raised-button
22+
color="primary"
23+
[disabled]="!undoWriteOffLoanForm.valid"
24+
*mifosxHasPermission="'UNDOWRITEOFF_LOAN'"
25+
>
26+
{{ 'labels.buttons.Submit' | translate }}
27+
</button>
28+
</mat-card-actions>
29+
</mat-card-content>
30+
</form>
31+
</mat-card>
32+
</div>
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
.container {
2+
margin: 20px;
3+
}
4+
5+
.mat-card {
6+
padding: 20px;
7+
}
8+
9+
.layout-column {
10+
display: flex;
11+
flex-direction: column;
12+
gap: 20px;
13+
}
14+
15+
.mat-card-actions {
16+
padding-top: 20px;
17+
}
18+
19+
.gap-5px {
20+
gap: 5px;
21+
}
22+
23+
.responsive-column {
24+
@media (width <= 768px) {
25+
flex-direction: column;
26+
align-items: stretch;
27+
}
28+
}
29+
30+
.m-b-20 {
31+
margin-bottom: 20px;
32+
}
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/** Angular Imports */
2+
import { Component, OnInit, Input } from '@angular/core';
3+
import {
4+
UntypedFormGroup,
5+
UntypedFormBuilder,
6+
Validators,
7+
ReactiveFormsModule
8+
} from '@angular/forms';
9+
import { ActivatedRoute, Router } from '@angular/router';
10+
11+
/** Custom Services */
12+
import { LoansService } from 'app/loans/loans.service';
13+
import { SettingsService } from 'app/settings/settings.service';
14+
import { AlertService } from 'app/core/alert/alert.service';
15+
import { Dates } from 'app/core/utils/dates';
16+
import { CdkTextareaAutosize } from '@angular/cdk/text-field';
17+
import { STANDALONE_SHARED_IMPORTS } from 'app/standalone-shared.module';
18+
19+
/**
20+
* Loan Undo Write-off Action
21+
*/
22+
@Component({
23+
selector: 'mifosx-undo-write-off',
24+
templateUrl: './undo-write-off.component.html',
25+
styleUrls: ['./undo-write-off.component.scss'],
26+
imports: [
27+
...STANDALONE_SHARED_IMPORTS,
28+
CdkTextareaAutosize
29+
]
30+
})
31+
export class UndoWriteOffComponent implements OnInit {
32+
@Input() dataObject: any;
33+
/** Loan Id */
34+
loanId: string;
35+
/** Minimum Date allowed. */
36+
minDate = new Date(2000, 0, 1);
37+
/** Maximum Date allowed. */
38+
maxDate = new Date();
39+
/** Undo Write-off Loan Form */
40+
undoWriteOffLoanForm: UntypedFormGroup;
41+
42+
/**
43+
* @param {FormBuilder} formBuilder Form Builder.
44+
* @param {LoansService} loanService Loan Service.
45+
* @param {ActivatedRoute} route Activated Route.
46+
* @param {Router} router Router for navigation.
47+
* @param {SettingsService} settingsService Settings Service
48+
*/
49+
constructor(
50+
private formBuilder: UntypedFormBuilder,
51+
private loanService: LoansService,
52+
private route: ActivatedRoute,
53+
private router: Router,
54+
private dateUtils: Dates,
55+
private settingsService: SettingsService,
56+
private alertService: AlertService
57+
) {
58+
this.loanId = this.route.snapshot.params['loanId'];
59+
}
60+
61+
/**
62+
* Creates the undo write-off loan form
63+
* and initialize with the required values
64+
*/
65+
ngOnInit() {
66+
this.maxDate = this.settingsService.businessDate;
67+
this.createUndoWriteOffLoanForm();
68+
}
69+
70+
/**
71+
* Creates the undo write-off loan form
72+
*/
73+
createUndoWriteOffLoanForm() {
74+
this.undoWriteOffLoanForm = this.formBuilder.group({
75+
note: ['']
76+
});
77+
}
78+
79+
/** Submits the undo write-off form */
80+
submit() {
81+
const undoWriteOffLoanFormData = this.undoWriteOffLoanForm.value;
82+
const locale = this.settingsService.language.code;
83+
const dateFormat = this.settingsService.dateFormat;
84+
const operationDate = this.settingsService.businessDate;
85+
const data = {
86+
...undoWriteOffLoanFormData,
87+
transactionDate: this.dateUtils.formatDate(operationDate && new Date(operationDate), dateFormat),
88+
transactionAmount: 0,
89+
dateFormat,
90+
locale
91+
};
92+
93+
this.loanService.submitLoanActionButton(this.loanId, data, 'undowriteoff').subscribe({
94+
next: (response: any) => {
95+
this.router.navigate(['../../general'], { relativeTo: this.route });
96+
},
97+
error: (error) => {
98+
console.error('Undo write-off failed:', error);
99+
this.alertService.alert({
100+
type: 'Undo Write-off Failed',
101+
message: 'An error occurred while processing the undo write-off transaction. Please try again or contact support if the problem persists.'
102+
});
103+
}
104+
});
105+
}
106+
}

src/app/loans/loans-view/loan-accounts-button-config.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,11 @@ export class LoansAccountButtonConfiguration {
124124
name: 'Recovery Payment',
125125
icon: 'briefcase',
126126
taskPermissionName: 'RECOVERYPAYMENT_LOAN'
127+
},
128+
{
129+
name: 'Undo Write-off',
130+
icon: 'undo',
131+
taskPermissionName: 'UNDOWRITEOFF_LOAN'
127132
}
128133
];
129134
break;

src/assets/translations/en-US.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2616,6 +2616,7 @@
26162616
"Recover From Guarantor": "Recover From Guarantor",
26172617
"Recovery Payment": "Recovery Payment",
26182618
"Reject": "Reject",
2619+
"Undo Write-off": "Undo Write-off",
26192620
"Reports": "Reports",
26202621
"Reschedule": "Reschedule",
26212622
"Savings": "Savings",
@@ -3428,7 +3429,8 @@
34283429
"Voluntary": "Voluntary",
34293430
"Write a note": "Write a note",
34303431
"“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.",
3431-
"Buy Down Fees": "Buy Down Fees"
3432+
"Buy Down Fees": "Buy Down Fees",
3433+
"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."
34323434
},
34333435
"titles": {
34343436
"Dashboard": "Dashboard",

0 commit comments

Comments
 (0)