Skip to content

Commit b28a59a

Browse files
WEB-813: Working Capital loan account modification
1 parent f82ad09 commit b28a59a

23 files changed

Lines changed: 217 additions & 62 deletions

src/app/core/http/error-handler.interceptor.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,15 @@ export class ErrorHandlerInterceptor implements HttpInterceptor {
4646
private handleError(response: HttpErrorResponse, request: HttpRequest<any>): Observable<HttpEvent<any>> {
4747
const status = response.status;
4848
let errorMessage = response.error.developerMessage || response.message;
49+
let parameterName: string | null = null;
4950
if (response.error.errors) {
5051
if (response.error.errors[0]) {
51-
errorMessage = response.error.errors[0].defaultUserMessage || response.error.errors[0].developerMessage;
52+
errorMessage =
53+
response.error.errors[0].defaultUserMessage.replace(/\\./g, ' ') ||
54+
response.error.errors[0].developerMessage.replace(/\\./g, ' ');
55+
}
56+
if ('parameterName' in response.error.errors[0]) {
57+
parameterName = response.error.errors[0].parameterName;
5258
}
5359
}
5460

@@ -63,9 +69,12 @@ export class ErrorHandlerInterceptor implements HttpInterceptor {
6369
} else if (status === 403 && errorMessage === 'The provided one time token is invalid') {
6470
this.alertService.alert({ type: 'Invalid Token', message: 'Invalid Token. Please try again!' });
6571
} else if (status === 400) {
72+
const message = parameterName
73+
? `[${parameterName}] ${errorMessage || 'Invalid parameters were passed in the request!'}`
74+
: `${errorMessage || 'Invalid parameters were passed in the request!'}`;
6675
this.alertService.alert({
6776
type: 'Bad Request',
68-
message: errorMessage || 'Invalid parameters were passed in the request!'
77+
message: message
6978
});
7079
} else if (status === 403) {
7180
this.alertService.alert({

src/app/loans/common-resolvers/loan-details.resolver.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ export class LoanDetailsResolver {
4040
if (resolvedProductType === LOAN_PRODUCT_TYPE.LOAN) {
4141
return this.loansService.getLoanAccountAssociationDetails(loanId);
4242
} else {
43-
return this.loansService.getWorkingCapitalLoannDetails(loanId);
43+
return this.loansService.getWorkingCapitalLoanDetails(loanId);
4444
}
4545
}
4646
}

src/app/loans/common-resolvers/loans-account-and-template.resolver.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,24 @@ import { Observable } from 'rxjs';
1515

1616
/** Custom Services */
1717
import { LoansService } from '../loans.service';
18+
import { LoanProductService } from 'app/products/loan-products/services/loan-product.service';
1819

1920
/**
2021
* Loan accounts template data resolver.
2122
*/
2223
@Injectable()
2324
export class LoansAccountAndTemplateResolver {
2425
private loansService = inject(LoansService);
26+
private loanProductService = inject(LoanProductService);
2527

2628
/**
2729
* Returns the loan account template data.
2830
* @returns {Observable<any>}
2931
*/
3032
resolve(route: ActivatedRouteSnapshot): Observable<any> {
3133
const loanId = route.paramMap.get('loanId') || route.parent.paramMap.get('loanId');
32-
return this.loansService.getLoansAccountAndTemplateResource(loanId);
34+
return this.loanProductService.isLoanProduct
35+
? this.loansService.getLoansAccountAndTemplateResource(loanId)
36+
: this.loansService.getWorkingCapitalLoanDetails(loanId);
3337
}
3438
}

src/app/loans/edit-loans-account/edit-loans-account.component.ts

Lines changed: 83 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -77,14 +77,22 @@ export class EditLoansAccountComponent extends LoanProductBaseComponent {
7777
super();
7878
this.loanProductService.initialize(LoanProductBaseComponent.resolveProductTypeDefault(this.route, 'loan'));
7979

80+
this.loanId = this.route.snapshot.params['loanId'];
8081
this.route.data.subscribe(
8182
(data: { loansAccountAndTemplate: any; loanProductsBasicDetails: LoanProductBasicDetails[] }) => {
8283
this.loansAccountAndTemplate = data.loansAccountAndTemplate;
83-
this.loansAccountProductTemplate = data.loansAccountAndTemplate;
84+
if (this.loanProductService.isLoanProduct) {
85+
this.loansAccountProductTemplate = data.loansAccountAndTemplate;
86+
} else if (this.loanProductService.isWorkingCapital) {
87+
this.loansAccountProductTemplate = data.loansAccountAndTemplate;
88+
this.getWorkingCapitalLoanProductTemplate(
89+
this.loansAccountProductTemplate.client.id,
90+
this.loansAccountProductTemplate.product.id
91+
);
92+
}
8493
this.loanProductsBasicDetails = data.loanProductsBasicDetails;
8594
}
8695
);
87-
this.loanId = this.route.snapshot.params['loanId'];
8896
}
8997

9098
/**
@@ -95,6 +103,15 @@ export class EditLoansAccountComponent extends LoanProductBaseComponent {
95103
const templateData: any = $event;
96104
this.loansAccountProductTemplate = templateData.loanData ? templateData.loanData : templateData;
97105
this.currencyCode = this.loansAccountProductTemplate.currency.code;
106+
this.productDetails = this.loansAccountProductTemplate.product;
107+
if (templateData.loanData) {
108+
this.loansAccountProductTemplate = templateData.loanData;
109+
this.loansAccountProductTemplate.options = {
110+
delinquencyBucketOptions: templateData.delinquencyBucketOptions,
111+
fundOptions: templateData.fundOptions,
112+
periodFrequencyTypeOptions: templateData.periodFrequencyTypeOptions
113+
};
114+
}
98115
if (this.loansAccountProductTemplate.loanProductId) {
99116
this.loansService
100117
.getLoansCollateralTemplateResource(this.loansAccountProductTemplate.loanProductId)
@@ -104,6 +121,12 @@ export class EditLoansAccountComponent extends LoanProductBaseComponent {
104121
}
105122
}
106123

124+
getWorkingCapitalLoanProductTemplate(clientId: number, productId: number) {
125+
this.loansService.getWorkingCapitalLoansAccountTemplate(clientId, productId).subscribe((response: any) => {
126+
this.setTemplate(response);
127+
});
128+
}
129+
107130
setProductType($event: any): void {
108131
this.productType = $event;
109132
this.loanProductService.initialize(this.productType);
@@ -131,7 +154,11 @@ export class EditLoansAccountComponent extends LoanProductBaseComponent {
131154
!this.loansAccountChargesStep?.pristine)
132155
);
133156
} else if (this.loanProductService.isWorkingCapital) {
134-
return false;
157+
return (
158+
this.loansAccountDetailsForm.valid &&
159+
this.loansAccountTermsForm.valid &&
160+
(!this.loansAccountDetailsForm.pristine || !this.loansAccountTermsForm.pristine)
161+
);
135162
}
136163
}
137164

@@ -241,15 +268,60 @@ export class EditLoansAccountComponent extends LoanProductBaseComponent {
241268
loansAccountData.allowPartialPeriodInterestCalculation = loansAccountData.allowPartialPeriodInterestCalculation;
242269
delete loansAccountData.allowPartialPeriodInterestCalculation;
243270

244-
this.loansService.updateLoansAccount(this.loanId, loansAccountData).subscribe((response: any) => {
245-
this.router.navigate(['../'], {
246-
queryParams: {
247-
productType: this.loanProductService.productType.value
248-
},
249-
relativeTo: this.route
271+
this.loansService
272+
.updateLoansAccount(this.loanProductService.loanAccountPath, this.loanId, loansAccountData)
273+
.subscribe((response: any) => {
274+
this.router.navigate(['../'], {
275+
queryParams: {
276+
productType: this.loanProductService.productType.value
277+
},
278+
relativeTo: this.route
279+
});
250280
});
251-
});
252281
}
253282

254-
submitWorkingCapitalProduct(): void {}
283+
submitWorkingCapitalProduct(): void {
284+
const locale = this.settingsService.language.code;
285+
const dateFormat = this.settingsService.dateFormat;
286+
const payload = {
287+
...this.loansAccount,
288+
clientId: this.loansAccountProductTemplate.client.id,
289+
submittedOnDate: this.dateUtils.formatDate(this.loansAccount.submittedOnDate, dateFormat),
290+
expectedDisbursementDate: this.dateUtils.formatDate(this.loansAccount.expectedDisbursementDate, dateFormat),
291+
locale,
292+
dateFormat
293+
};
294+
295+
if (this.productDetails.allowAttributeOverrides) {
296+
if (
297+
!Object.hasOwn(this.productDetails.allowAttributeOverrides, 'periodPaymentFrequency') ||
298+
this.productDetails.allowAttributeOverrides.periodPaymentFrequency === false
299+
) {
300+
delete payload['repaymentEvery'];
301+
}
302+
if (
303+
!Object.hasOwn(this.productDetails.allowAttributeOverrides, 'periodPaymentFrequencyType') ||
304+
this.productDetails.allowAttributeOverrides.periodPaymentFrequencyType === false
305+
) {
306+
delete payload['repaymentFrequencyType'];
307+
}
308+
if (
309+
!Object.hasOwn(this.productDetails.allowAttributeOverrides, 'discountDefault') ||
310+
this.productDetails.allowAttributeOverrides.discountDefault === false
311+
) {
312+
delete payload['discount'];
313+
}
314+
}
315+
316+
this.loansService
317+
.updateLoansAccount(this.loanProductService.loanAccountPath, this.loanId, payload)
318+
.subscribe((response: any) => {
319+
this.router.navigate(['../'], {
320+
queryParams: {
321+
productType: this.loanProductService.productType.value
322+
},
323+
relativeTo: this.route
324+
});
325+
});
326+
}
255327
}

src/app/loans/loans-account-stepper/loans-account-details-step/loans-account-details-step.component.html

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,11 @@ <h3 class="mat-h3 flex-fill">{{ 'labels.heading.Savings Linkage' | translate }}<
172172
<fa-icon icon="arrow-right" class="m-l-10"></fa-icon>
173173
</button>
174174
@if (loanId) {
175-
<button mat-raised-button [routerLink]="['../', 'general']">
175+
<button
176+
mat-raised-button
177+
[routerLink]="['../', 'general']"
178+
[queryParams]="{ productType: loanProductService.productType.value }"
179+
>
176180
{{ 'labels.buttons.Cancel' | translate }}
177181
</button>
178182
}

src/app/loans/loans-account-stepper/loans-account-details-step/loans-account-details-step.component.ts

Lines changed: 48 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -118,34 +118,41 @@ export class LoansAccountDetailsStepComponent extends LoanProductBaseComponent i
118118
this.placeHolderLabel = this.translateService.instant('labels.text.Search');
119119
this.noEntriesFoundLabel = this.translateService.instant('labels.text.No data found');
120120
this.maxDate = this.settingsService.maxFutureDate;
121-
this.productList = this.loanProductsBasicDetails.sort(this.commons.dynamicSort('name'));
121+
this.productList = this.loanProductsBasicDetails
122+
? this.loanProductsBasicDetails.sort(this.commons.dynamicSort('name'))
123+
: [];
122124
if (this.loansAccountTemplate) {
125+
this.addFormControlsBasedOnProductType();
126+
let loanProductId: number | null = null;
127+
this.loansAccountDetailsForm.patchValue({
128+
fundId: this.loansAccountTemplate.fundId,
129+
submittedOnDate:
130+
this.loansAccountTemplate.timeline.submittedOnDate &&
131+
new Date(this.loansAccountTemplate.timeline.submittedOnDate),
132+
expectedDisbursementDate:
133+
this.loansAccountTemplate.timeline.expectedDisbursementDate &&
134+
new Date(this.loansAccountTemplate.timeline.expectedDisbursementDate),
135+
externalId: this.loansAccountTemplate.externalId
136+
});
123137
if (this.loansAccountTemplate.loanProductId) {
124-
this.addFormControlsBasedOnProductType();
138+
loanProductId = this.loansAccountTemplate.loanProductId;
125139
this.loansAccountDetailsForm.patchValue({
126-
productId: this.loansAccountTemplate.loanProductId,
127-
submittedOnDate:
128-
this.loansAccountTemplate.timeline.submittedOnDate &&
129-
new Date(this.loansAccountTemplate.timeline.submittedOnDate),
130140
loanOfficerId: this.loansAccountTemplate.loanOfficerId,
131-
loanPurposeId: this.loansAccountTemplate.loanPurposeId,
132-
fundId: this.loansAccountTemplate.fundId,
133-
expectedDisbursementDate:
134-
this.loansAccountTemplate.timeline.expectedDisbursementDate &&
135-
new Date(this.loansAccountTemplate.timeline.expectedDisbursementDate),
136-
externalId: this.loansAccountTemplate.externalId
141+
loanPurposeId: this.loansAccountTemplate.loanPurposeId
137142
});
138-
this.productSelected = this.loanProductsBasicDetails.find(
139-
(p: LoanProductBasicDetails) =>
140-
p.productType === this.loanProductService.productType.value &&
141-
p.id === this.loansAccountTemplate.loanProductId
142-
);
143-
if (this.productSelected) {
144-
this.loansAccountDetailsForm.patchValue({
145-
productId: this.productSelected.shortName
146-
});
147-
this.loanProductSelected = true;
148-
}
143+
} else if (this.loanProductService.isWorkingCapital && this.loansAccountTemplate.product) {
144+
loanProductId = this.loansAccountTemplate.product.id;
145+
}
146+
this.productSelected = this.loanProductsBasicDetails.find(
147+
(p: LoanProductBasicDetails) =>
148+
p.productType === this.loanProductService.productType.value && p.id === loanProductId
149+
);
150+
if (this.productSelected) {
151+
this.loansAccountDetailsForm.patchValue({
152+
productId: this.productSelected.shortName
153+
});
154+
this.loanProductSelected = true;
155+
this.getProductTemplate(false);
149156
}
150157
}
151158
this.filterFormCtrl.valueChanges.pipe(takeUntil(this._onDestroy)).subscribe(() => {
@@ -220,16 +227,24 @@ export class LoansAccountDetailsStepComponent extends LoanProductBaseComponent i
220227
this.productSelected = this.loanProductsBasicDetails.find(
221228
(p: LoanProductBasicDetails) => p.shortName === productShortName
222229
);
230+
this.getProductTemplate(true);
231+
}
232+
233+
getProductTemplate(emitEvent: boolean): void {
223234
if (this.productSelected) {
224235
this.loanProductService.initialize(this.productSelected.productType);
225-
const entityId = this.loansAccountTemplate.clientId
226-
? this.loansAccountTemplate.clientId
227-
: this.loansAccountTemplate.group.id;
228-
const isGroup: boolean = this.loansAccountTemplate.clientId ? false : true;
229-
230-
this.loansProductType.emit(this.productSelected.productType);
231-
this.addFormControlsBasedOnProductType();
236+
if (emitEvent) {
237+
this.loansProductType.emit(this.productSelected.productType);
238+
this.addFormControlsBasedOnProductType();
239+
}
232240
if (this.loanProductService.isLoanProduct) {
241+
const entityId = this.loansAccountTemplate.clientId
242+
? this.loansAccountTemplate.clientId
243+
: this.loansAccountTemplate.group
244+
? this.loansAccountTemplate.group.id
245+
: null;
246+
247+
const isGroup: boolean = this.loansAccountTemplate.clientId ? false : true;
233248
this.loansService
234249
.getLoansAccountTemplateResource(entityId, isGroup, this.productSelected.id)
235250
.subscribe((response: any) => {
@@ -246,6 +261,9 @@ export class LoansAccountDetailsStepComponent extends LoanProductBaseComponent i
246261
}
247262
});
248263
} else if (this.loanProductService.isWorkingCapital) {
264+
const entityId = this.loansAccountTemplate.client
265+
? this.loansAccountTemplate.client.id
266+
: this.route.parent.snapshot.params['clientId'];
249267
this.loansService
250268
.getWorkingCapitalLoansAccountTemplate(entityId, this.productSelected.id)
251269
.subscribe((response: any) => {

src/app/loans/loans-account-stepper/loans-account-preview-step/loans-account-preview-step.component.html

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -457,7 +457,11 @@ <h3 class="mat-h3 flex-98">{{ 'labels.heading.Overdue Charges' | translate }}</h
457457
<fa-icon icon="arrow-left" class="m-r-10"></fa-icon>
458458
{{ 'labels.buttons.Previous' | translate }}
459459
</button>
460-
<button mat-raised-button [routerLink]="['../..']">
460+
<button
461+
mat-raised-button
462+
[routerLink]="['../..']"
463+
[queryParams]="{ productType: loanProductService.productType.value }"
464+
>
461465
{{ 'labels.buttons.Cancel' | translate }}
462466
</button>
463467
<button mat-raised-button color="primary" (click)="submitEvent.emit()">

src/app/loans/loans-account-stepper/loans-account-terms-step/loans-account-terms-step.component.html

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,25 @@ <h4 class="mat-h4 flex-98">
2828
<mat-form-field class="flex-48">
2929
<mat-label>{{ 'labels.inputs.Total Payment' | translate }} {{ 'labels.inputs.Volume' | translate }}</mat-label>
3030
<input type="number" matInput required formControlName="totalPayment" />
31+
@if (loansAccountTermsForm.controls.totalPayment.hasError('highAmountValue')) {
32+
<mat-error>
33+
{{ 'labels.inputs.Total Payment' | translate }} {{ 'labels.commons.is' | translate }}
34+
<strong>{{ 'labels.commons.higher than allowed' | translate }}</strong>
35+
</mat-error>
36+
}
3137
</mat-form-field>
3238

3339
<mat-form-field class="flex-48">
3440
<mat-label>{{ 'labels.inputs.Discount' | translate }}</mat-label>
3541
<input type="number" matInput formControlName="discount" />
3642
</mat-form-field>
3743

38-
<mat-form-field class="flex-28">
44+
<mat-form-field class="flex-48">
3945
<mat-label>{{ 'labels.inputs.Period Payment Rate' | translate }}</mat-label>
4046
<input type="number" matInput formControlName="periodPaymentRate" />
4147
</mat-form-field>
4248

43-
<mat-form-field class="flex-23">
49+
<mat-form-field class="flex-24">
4450
<mat-label>{{ 'labels.inputs.Period Payment Frequency' | translate }}</mat-label>
4551
<input
4652
type="number"
@@ -57,7 +63,7 @@ <h4 class="mat-h4 flex-98">
5763
}
5864
</mat-form-field>
5965

60-
<mat-form-field class="flex-23">
66+
<mat-form-field class="flex-24">
6167
<mat-label>{{ 'labels.inputs.Period Payment Frequency Type' | translate }}</mat-label>
6268
<mat-select formControlName="repaymentFrequencyType" required>
6369
@for (repaymentFrequencyType of termFrequencyTypeData; track repaymentFrequencyType) {
@@ -791,7 +797,11 @@ <h4 class="mat-h4 flex-98">{{ 'labels.heading.Collaterals Data' | translate }}</
791797
<fa-icon icon="arrow-right" class="m-l-10"></fa-icon>
792798
</button>
793799
@if (loanId) {
794-
<button mat-raised-button [routerLink]="['../', 'general']">
800+
<button
801+
mat-raised-button
802+
[routerLink]="['../', 'general']"
803+
[queryParams]="{ productType: loanProductService.productType.value }"
804+
>
795805
{{ 'labels.buttons.Cancel' | translate }}
796806
</button>
797807
}

0 commit comments

Comments
 (0)