Skip to content

Commit 901d4f6

Browse files
committed
WEB-95: WEB-95 Fix problems with GLIM application: saved total, "Moratorium", "Overdue Charges""
1 parent 75a489d commit 901d4f6

File tree

7 files changed

+120
-117
lines changed

7 files changed

+120
-117
lines changed

src/app/app.module.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
/** Angular Imports */
1010
import { NgModule } from '@angular/core';
1111
import { BrowserModule } from '@angular/platform-browser';
12+
import { I18nService } from './core/i18n/i18n.service';
1213
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
1314
import {
1415
HttpBackend,
@@ -139,7 +140,8 @@ export function HttpLoaderFactory(http: HttpClient) {
139140
provide: HTTP_INTERCEPTORS,
140141
useClass: !environment.OIDC.oidcServerEnabled ? TokenInterceptor : ZitadelTokenInterceptor,
141142
multi: true
142-
}
143+
},
144+
I18nService
143145
]
144146
})
145147
export class AppModule {}

src/app/loans/glim-account/create-glim-account/create-glim-account.component.ts

Lines changed: 30 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -185,58 +185,42 @@ export class CreateGlimAccountComponent {
185185
};
186186
}
187187

188-
setData(client: any, totalLoan: number): any {
188+
setData(applicationId: number, client: any, totalLoan: number, isFirst: boolean, isLast: boolean): any {
189189
const locale = this.settingsService.language.code;
190190
const dateFormat = this.settingsService.dateFormat;
191191
// const monthDayFormat = 'dd MMMM';
192-
const data = {
192+
const data: any = {
193193
...this.loansAccount,
194-
charges: (this.loansAccount.charges ?? [])
195-
.map((charge: any) => {
196-
const chargeId = charge.chargeId ?? charge.id;
197-
if (chargeId == null) {
198-
return null;
199-
}
200-
const mappedCharge: any = {
201-
chargeId,
202-
amount: charge.amount
203-
};
204-
if (charge.id && charge.id !== chargeId) {
205-
mappedCharge.id = charge.id;
206-
}
207-
if (charge.dueDate) {
208-
mappedCharge.dueDate = this.dateUtils.formatDate(charge.dueDate, dateFormat);
209-
}
210-
if (charge.feeInterval !== undefined) {
211-
mappedCharge.feeInterval = charge.feeInterval;
212-
}
213-
if (charge.feeOnMonthDay !== undefined) {
214-
mappedCharge.feeOnMonthDay = charge.feeOnMonthDay;
215-
}
216-
return mappedCharge;
217-
})
218-
.filter(Boolean),
194+
charges: this.loansAccount.charges.map((charge: any) => ({
195+
chargeId: charge.id,
196+
amount: charge.amount,
197+
currency: charge.currency
198+
})),
219199
clientId: client.id,
220200
totalLoan: totalLoan,
221201
loanType: 'glim',
202+
applicationId: applicationId,
222203
amortizationType: 1,
223-
isParentAccount: true,
224204
principal: client.principal,
225205
syncDisbursementWithMeeting: false,
226206
expectedDisbursementDate: this.dateUtils.formatDate(this.loansAccount.expectedDisbursementDate, dateFormat),
227207
submittedOnDate: this.dateUtils.formatDate(this.loansAccount.submittedOnDate, dateFormat),
228-
dateFormat,
229-
// monthDayFormat,
230-
locale
208+
dateFormat: dateFormat,
209+
locale: locale,
210+
groupId: this.loansAccountTemplate.group.id
231211
};
232-
data.groupId = this.loansAccountTemplate.group.id;
233-
212+
if (isFirst) {
213+
data.isParentAccount = true;
214+
}
215+
if (isLast) {
216+
data.lastApplication = true;
217+
}
234218
delete data.principalAmount;
235-
// TODO: 2025-03-17: Apparently (?!) unsupported for GLIM
236219
delete data.allowPartialPeriodInterestCalculation;
237220
delete data.multiDisburseLoan;
238221
delete data.isFloatingInterestRate;
239-
222+
delete data.moratoriumPrincipal;
223+
delete data.moratoriumInterest;
240224
return JSON.stringify(data);
241225
}
242226

@@ -245,12 +229,17 @@ export class CreateGlimAccountComponent {
245229
const requestData = [];
246230
const memberSelected = this.selectedMembers?.selectedMembers ?? [];
247231
const totalLoan = this.totalLoanAmount();
232+
const applicationId = Math.floor(1000000000 + Math.random() * 9000000000);
233+
248234
for (let index = 0; index < memberSelected.length; index++) {
235+
const isFirst = index === 0;
236+
const isLast = index === memberSelected.length - 1;
249237
requestData.push({
250238
requestId: index.toString(),
239+
reference: index === 0 ? null : (index - 1).toString(),
251240
method: 'POST',
252241
relativeUrl: 'loans',
253-
body: this.setData(memberSelected[index], totalLoan)
242+
body: this.setData(applicationId, memberSelected[index], totalLoan, isFirst, isLast)
254243
});
255244
}
256245
return requestData;
@@ -265,57 +254,10 @@ export class CreateGlimAccountComponent {
265254
return total;
266255
}
267256

268-
/**
269-
* Creates a new GLIM account.
270-
*/
271-
submit() {
272-
this.selectedMembers = this.loansActiveClientMembers?.selectedClientMembers;
273-
const memberSelected = this.loansActiveClientMembers?.selectedClientMembers?.selectedMembers ?? [];
274-
if (!memberSelected.length) return;
275-
const gsimMemberIds = new Set(this.dataSource.map((m: any) => Number(m.id)));
276-
for (const member of memberSelected) {
277-
const memberId = Number(member.id);
278-
// Validate savings account ownership
279-
const ownerId = Number(member.linkAccountOwnerId);
280-
if (member.linkAccountId && member.linkAccountOwnerId && ownerId !== memberId) {
281-
this.i18nService.translate('errors.linkedSavingsAccountOwnership').subscribe((msg: string) => {
282-
this.notify({ defaultUserMessage: msg, errors: [] }, { memberId });
283-
});
284-
return;
285-
}
286-
// Validate GSIM membership
287-
if (!gsimMemberIds.has(memberId)) {
288-
this.i18nService.translate('errors.clientNotInGSIM', { id: memberId }).subscribe((msg: string) => {
289-
this.notify({ defaultUserMessage: msg, errors: [] }, { memberId });
290-
});
291-
return;
292-
}
293-
}
294-
295-
// Use date format from settingsService for interestChargedFromDate
296-
const data = this.buildRequestData();
297-
this.loansService.createGlimAccount(data).subscribe((response: any) => {
298-
const body = JSON.parse(response[0].body);
299-
if (body.glimId) {
300-
this.router.navigate(
301-
[
302-
'../',
303-
body.glimId
304-
],
305-
{ relativeTo: this.route }
306-
);
307-
} else {
308-
this.notify(body, { batchSize: data.length });
309-
}
310-
});
311-
}
312-
313-
notify(body: any, context?: { [k: string]: unknown }) {
314-
const parts: string[] = [String(body?.defaultUserMessage ?? '')];
315-
if (Array.isArray(body?.errors)) {
316-
for (const e of body.errors) parts.push(String(e?.developerMessage ?? ''));
317-
}
318-
if (context) parts.push(`Context: ${JSON.stringify(context)}`);
319-
console.error(parts.join(' ').trim());
257+
notify(body: any, data: any) {
258+
let message = body.defaultUserMessage + ' ';
259+
body.errors?.forEach((error: any) => (message += error.developerMessage + ' '));
260+
message += 'Data: ' + JSON.stringify(data);
261+
console.error(message);
320262
}
321263
}

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

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
<ng-container matColumnDef="name">
3535
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.name' | translate }}</th>
3636
<td mat-cell *matCellDef="let charge">
37-
{{ charge.name + ', ' + (charge.currency?.displaySymbol || '') }}
37+
{{ charge.name }}<span *ngIf="charge.currency">, {{ charge.currency.displaySymbol }}</span>
3838
</td>
3939
</ng-container>
4040

@@ -49,7 +49,13 @@
4949
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Amount' | translate }}</th>
5050
<td mat-cell *matCellDef="let charge">
5151
{{ charge.amount }}
52-
<button mat-icon-button color="primary" (click)="editChargeAmount(charge)">
52+
<button
53+
mat-icon-button
54+
color="primary"
55+
(click)="editChargeAmount(charge)"
56+
type="button"
57+
aria-label="Edit charge amount"
58+
>
5359
<fa-icon icon="pen"></fa-icon>
5460
</button>
5561
</td>
@@ -102,7 +108,7 @@
102108
<ng-container matColumnDef="action">
103109
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Actions' | translate }}</th>
104110
<td mat-cell *matCellDef="let charge">
105-
<button mat-icon-button color="warn" (click)="deleteCharge(charge)">
111+
<button mat-icon-button color="warn" (click)="deleteCharge(charge)" type="button" aria-label="Delete charge">
106112
<fa-icon icon="trash"></fa-icon>
107113
</button>
108114
</td>
@@ -119,7 +125,9 @@ <h4 class="mat-h4 flex-98">{{ 'labels.heading.Overdue Charges' | translate }}</h
119125
<table mat-table class="mat-elevation-z1" [dataSource]="overDueChargesDataSource">
120126
<ng-container matColumnDef="name">
121127
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.name' | translate }}</th>
122-
<td mat-cell *matCellDef="let charge">{{ charge.name + ', ' + (charge.currency?.displaySymbol || '') }}</td>
128+
<td mat-cell *matCellDef="let charge">
129+
{{ charge.name }}<span *ngIf="charge.currency">, {{ charge.currency.displaySymbol }}</span>
130+
</td>
123131
</ng-container>
124132

125133
<ng-container matColumnDef="type">
@@ -129,7 +137,18 @@ <h4 class="mat-h4 flex-98">{{ 'labels.heading.Overdue Charges' | translate }}</h
129137

130138
<ng-container matColumnDef="amount">
131139
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Amount' | translate }}</th>
132-
<td mat-cell *matCellDef="let charge">{{ charge.amount | formatNumber }}</td>
140+
<td mat-cell *matCellDef="let charge">
141+
{{ charge.amount | formatNumber }}
142+
<button
143+
mat-icon-button
144+
color="primary"
145+
(click)="editOverdueChargeAmount(charge)"
146+
type="button"
147+
aria-label="Edit overdue charge amount"
148+
>
149+
<fa-icon icon="pen"></fa-icon>
150+
</button>
151+
</td>
133152
</ng-container>
134153

135154
<ng-container matColumnDef="collectedon">
@@ -143,17 +162,15 @@ <h4 class="mat-h4 flex-98">{{ 'labels.heading.Overdue Charges' | translate }}</h
143162
</div>
144163

145164
<div class="layout-row responsive-column align-center gap-2px margin-t">
146-
<button mat-raised-button matStepperPrevious>
165+
<button mat-raised-button matStepperPrevious type="button">
147166
<fa-icon icon="arrow-left" class="m-r-10"></fa-icon>
148167
{{ 'labels.buttons.Previous' | translate }}
149168
</button>
150-
<button mat-raised-button matStepperNext>
169+
<button mat-raised-button matStepperNext type="button">
151170
{{ 'labels.buttons.Next' | translate }}
152171
<fa-icon icon="arrow-right" class="m-l-10"></fa-icon>
153172
</button>
154-
@if (loanId) {
155-
<button mat-raised-button [routerLink]="['../', 'general']">
156-
{{ 'labels.buttons.Cancel' | translate }}
157-
</button>
158-
}
173+
<button mat-raised-button *ngIf="loanId" [routerLink]="['../', 'general']" type="button">
174+
{{ 'labels.buttons.Cancel' | translate }}
175+
</button>
159176
</div>

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,32 @@ export class LoansAccountChargesStepComponent implements OnInit, OnChanges {
331331
});
332332
}
333333

334+
editOverdueChargeAmount(charge: { amount: number; [key: string]: any }) {
335+
const formfields: FormfieldBase[] = [
336+
new InputBase({
337+
controlName: 'amount',
338+
label: 'Amount',
339+
value: charge.amount,
340+
type: 'number',
341+
required: false
342+
})
343+
];
344+
const data = {
345+
title: 'Edit Overdue Charge Amount',
346+
layout: { addButtonText: 'Confirm' },
347+
formfields: formfields
348+
};
349+
const editNoteDialogRef = this.dialog.open(FormDialogComponent, { data });
350+
editNoteDialogRef.afterClosed().subscribe((response?: { data?: { value: { amount: number } } }) => {
351+
if (response?.data) {
352+
const newCharge = { ...charge, amount: response.data.value.amount };
353+
this.overDueChargesDataSource.splice(this.overDueChargesDataSource.indexOf(charge), 1, newCharge);
354+
this.overDueChargesDataSource = this.overDueChargesDataSource.concat([]);
355+
this.pristine = false;
356+
}
357+
});
358+
}
359+
334360
get isValid() {
335361
return true;
336362
// !this.activeClientMembers ||

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -344,10 +344,10 @@ <h3 class="mat-h3 flex-fill">{{ 'labels.heading.Charges' | translate }}</h3>
344344
}
345345
@if (
346346
!(
347-
charge.chargeTimeType.value === 'Monthly Fee' ||
348-
charge.chargeTimeType.value === 'Annual Fee' ||
349-
charge.chargeTimeType.value === 'Specified due date' ||
350-
charge.chargeTimeType.value === 'Weekly Fee'
347+
charge.chargeTimeType?.value === 'Monthly Fee' ||
348+
charge.chargeTimeType?.value === 'Annual Fee' ||
349+
charge.chargeTimeType?.value === 'Specified due date' ||
350+
charge.chargeTimeType?.value === 'Weekly Fee'
351351
)
352352
) {
353353
<span>

0 commit comments

Comments
 (0)