Skip to content

Commit 91ea1ac

Browse files
committed
WEB-95: WEB-95 Fix problems with GLIM application: saved total, "Moratorium", "Overdue Charges""
1 parent 3ec93a7 commit 91ea1ac

File tree

7 files changed

+116
-114
lines changed

7 files changed

+116
-114
lines changed

src/app/app.module.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/** Angular Imports */
22
import { NgModule } from '@angular/core';
33
import { BrowserModule } from '@angular/platform-browser';
4+
import { I18nService } from './core/i18n/i18n.service';
45
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
56
import {
67
HttpBackend,
@@ -129,7 +130,8 @@ export function HttpLoaderFactory(http: HttpClient) {
129130
provide: HTTP_INTERCEPTORS,
130131
useClass: !environment.OIDC.oidcServerEnabled ? TokenInterceptor : ZitadelTokenInterceptor,
131132
multi: true
132-
}
133+
},
134+
I18nService
133135
]
134136
})
135137
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
@@ -177,58 +177,42 @@ export class CreateGlimAccountComponent {
177177
};
178178
}
179179

180-
setData(client: any, totalLoan: number): any {
180+
setData(applicationId: number, client: any, totalLoan: number, isFirst: boolean, isLast: boolean): any {
181181
const locale = this.settingsService.language.code;
182182
const dateFormat = this.settingsService.dateFormat;
183183
// const monthDayFormat = 'dd MMMM';
184-
const data = {
184+
const data: any = {
185185
...this.loansAccount,
186-
charges: (this.loansAccount.charges ?? [])
187-
.map((charge: any) => {
188-
const chargeId = charge.chargeId ?? charge.id;
189-
if (chargeId == null) {
190-
return null;
191-
}
192-
const mappedCharge: any = {
193-
chargeId,
194-
amount: charge.amount
195-
};
196-
if (charge.id && charge.id !== chargeId) {
197-
mappedCharge.id = charge.id;
198-
}
199-
if (charge.dueDate) {
200-
mappedCharge.dueDate = this.dateUtils.formatDate(charge.dueDate, dateFormat);
201-
}
202-
if (charge.feeInterval !== undefined) {
203-
mappedCharge.feeInterval = charge.feeInterval;
204-
}
205-
if (charge.feeOnMonthDay !== undefined) {
206-
mappedCharge.feeOnMonthDay = charge.feeOnMonthDay;
207-
}
208-
return mappedCharge;
209-
})
210-
.filter(Boolean),
186+
charges: this.loansAccount.charges.map((charge: any) => ({
187+
chargeId: charge.id,
188+
amount: charge.amount,
189+
currency: charge.currency
190+
})),
211191
clientId: client.id,
212192
totalLoan: totalLoan,
213193
loanType: 'glim',
194+
applicationId: applicationId,
214195
amortizationType: 1,
215-
isParentAccount: true,
216196
principal: client.principal,
217197
syncDisbursementWithMeeting: false,
218198
expectedDisbursementDate: this.dateUtils.formatDate(this.loansAccount.expectedDisbursementDate, dateFormat),
219199
submittedOnDate: this.dateUtils.formatDate(this.loansAccount.submittedOnDate, dateFormat),
220-
dateFormat,
221-
// monthDayFormat,
222-
locale
200+
dateFormat: dateFormat,
201+
locale: locale,
202+
groupId: this.loansAccountTemplate.group.id
223203
};
224-
data.groupId = this.loansAccountTemplate.group.id;
225-
204+
if (isFirst) {
205+
data.isParentAccount = true;
206+
}
207+
if (isLast) {
208+
data.lastApplication = true;
209+
}
226210
delete data.principalAmount;
227-
// TODO: 2025-03-17: Apparently (?!) unsupported for GLIM
228211
delete data.allowPartialPeriodInterestCalculation;
229212
delete data.multiDisburseLoan;
230213
delete data.isFloatingInterestRate;
231-
214+
delete data.moratoriumPrincipal;
215+
delete data.moratoriumInterest;
232216
return JSON.stringify(data);
233217
}
234218

@@ -237,12 +221,17 @@ export class CreateGlimAccountComponent {
237221
const requestData = [];
238222
const memberSelected = this.selectedMembers?.selectedMembers ?? [];
239223
const totalLoan = this.totalLoanAmount();
224+
const applicationId = Math.floor(1000000000 + Math.random() * 9000000000);
225+
240226
for (let index = 0; index < memberSelected.length; index++) {
227+
const isFirst = index === 0;
228+
const isLast = index === memberSelected.length - 1;
241229
requestData.push({
242230
requestId: index.toString(),
231+
reference: index === 0 ? null : (index - 1).toString(),
243232
method: 'POST',
244233
relativeUrl: 'loans',
245-
body: this.setData(memberSelected[index], totalLoan)
234+
body: this.setData(applicationId, memberSelected[index], totalLoan, isFirst, isLast)
246235
});
247236
}
248237
return requestData;
@@ -257,57 +246,10 @@ export class CreateGlimAccountComponent {
257246
return total;
258247
}
259248

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

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
@@ -26,7 +26,7 @@
2626
<ng-container matColumnDef="name">
2727
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.name' | translate }}</th>
2828
<td mat-cell *matCellDef="let charge">
29-
{{ charge.name + ', ' + (charge.currency?.displaySymbol || '') }}
29+
{{ charge.name }}<span *ngIf="charge.currency">, {{ charge.currency.displaySymbol }}</span>
3030
</td>
3131
</ng-container>
3232

@@ -41,7 +41,13 @@
4141
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Amount' | translate }}</th>
4242
<td mat-cell *matCellDef="let charge">
4343
{{ charge.amount }}
44-
<button mat-icon-button color="primary" (click)="editChargeAmount(charge)">
44+
<button
45+
mat-icon-button
46+
color="primary"
47+
(click)="editChargeAmount(charge)"
48+
type="button"
49+
aria-label="Edit charge amount"
50+
>
4551
<fa-icon icon="pen"></fa-icon>
4652
</button>
4753
</td>
@@ -94,7 +100,7 @@
94100
<ng-container matColumnDef="action">
95101
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Actions' | translate }}</th>
96102
<td mat-cell *matCellDef="let charge">
97-
<button mat-icon-button color="warn" (click)="deleteCharge(charge)">
103+
<button mat-icon-button color="warn" (click)="deleteCharge(charge)" type="button" aria-label="Delete charge">
98104
<fa-icon icon="trash"></fa-icon>
99105
</button>
100106
</td>
@@ -111,7 +117,9 @@ <h4 class="mat-h4 flex-98">{{ 'labels.heading.Overdue Charges' | translate }}</h
111117
<table mat-table class="mat-elevation-z1" [dataSource]="overDueChargesDataSource">
112118
<ng-container matColumnDef="name">
113119
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.name' | translate }}</th>
114-
<td mat-cell *matCellDef="let charge">{{ charge.name + ', ' + (charge.currency?.displaySymbol || '') }}</td>
120+
<td mat-cell *matCellDef="let charge">
121+
{{ charge.name }}<span *ngIf="charge.currency">, {{ charge.currency.displaySymbol }}</span>
122+
</td>
115123
</ng-container>
116124

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

122130
<ng-container matColumnDef="amount">
123131
<th mat-header-cell *matHeaderCellDef>{{ 'labels.inputs.Amount' | translate }}</th>
124-
<td mat-cell *matCellDef="let charge">{{ charge.amount | formatNumber }}</td>
132+
<td mat-cell *matCellDef="let charge">
133+
{{ charge.amount | formatNumber }}
134+
<button
135+
mat-icon-button
136+
color="primary"
137+
(click)="editOverdueChargeAmount(charge)"
138+
type="button"
139+
aria-label="Edit overdue charge amount"
140+
>
141+
<fa-icon icon="pen"></fa-icon>
142+
</button>
143+
</td>
125144
</ng-container>
126145

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

137156
<div class="layout-row responsive-column align-center gap-2px margin-t">
138-
<button mat-raised-button matStepperPrevious>
157+
<button mat-raised-button matStepperPrevious type="button">
139158
<fa-icon icon="arrow-left" class="m-r-10"></fa-icon>
140159
{{ 'labels.buttons.Previous' | translate }}
141160
</button>
142-
<button mat-raised-button matStepperNext>
161+
<button mat-raised-button matStepperNext type="button">
143162
{{ 'labels.buttons.Next' | translate }}
144163
<fa-icon icon="arrow-right" class="m-l-10"></fa-icon>
145164
</button>
146-
@if (loanId) {
147-
<button mat-raised-button [routerLink]="['../', 'general']">
148-
{{ 'labels.buttons.Cancel' | translate }}
149-
</button>
150-
}
165+
<button mat-raised-button *ngIf="loanId" [routerLink]="['../', 'general']" type="button">
166+
+ {{ 'labels.buttons.Cancel' | translate }} +
167+
</button>
151168
</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
@@ -323,6 +323,32 @@ export class LoansAccountChargesStepComponent implements OnInit, OnChanges {
323323
});
324324
}
325325

326+
editOverdueChargeAmount(charge: { amount: number; [key: string]: any }) {
327+
const formfields: FormfieldBase[] = [
328+
new InputBase({
329+
controlName: 'amount',
330+
label: 'Amount',
331+
value: charge.amount,
332+
type: 'number',
333+
required: false
334+
})
335+
];
336+
const data = {
337+
title: 'Edit Overdue Charge Amount',
338+
layout: { addButtonText: 'Confirm' },
339+
formfields: formfields
340+
};
341+
const editNoteDialogRef = this.dialog.open(FormDialogComponent, { data });
342+
editNoteDialogRef.afterClosed().subscribe((response?: { data?: { value: { amount: number } } }) => {
343+
if (response?.data) {
344+
const newCharge = { ...charge, amount: response.data.value.amount };
345+
this.overDueChargesDataSource.splice(this.overDueChargesDataSource.indexOf(charge), 1, newCharge);
346+
this.overDueChargesDataSource = this.overDueChargesDataSource.concat([]);
347+
this.pristine = false;
348+
}
349+
});
350+
}
351+
326352
get isValid() {
327353
return true;
328354
// !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
@@ -332,10 +332,10 @@ <h3 class="mat-h3 flex-fill">{{ 'labels.heading.Charges' | translate }}</h3>
332332
}
333333
@if (
334334
!(
335-
charge.chargeTimeType.value === 'Monthly Fee' ||
336-
charge.chargeTimeType.value === 'Annual Fee' ||
337-
charge.chargeTimeType.value === 'Specified due date' ||
338-
charge.chargeTimeType.value === 'Weekly Fee'
335+
charge.chargeTimeType?.value === 'Monthly Fee' ||
336+
charge.chargeTimeType?.value === 'Annual Fee' ||
337+
charge.chargeTimeType?.value === 'Specified due date' ||
338+
charge.chargeTimeType?.value === 'Weekly Fee'
339339
)
340340
) {
341341
<span>

0 commit comments

Comments
 (0)