Enhacement for Charge management (#1659)

Co-authored-by: Jose Alberto Hernandez <alberto@MacBook-Pro.local>
This commit is contained in:
José Alberto Hernández
2023-01-29 00:56:38 -06:00
committed by GitHub
co-authored by Jose Alberto Hernandez
parent 480809c4cc
commit ffea817f76
14 changed files with 115 additions and 60 deletions
-1
View File
@@ -81,7 +81,6 @@ const routes: Routes = [
path: '',
component: LoansViewComponent,
resolve: {
loanDetailsData: LoanDetailsResolver,
loanDatatables: LoanDatatablesResolver
},
children: [
@@ -3,12 +3,24 @@
<ng-container *ngIf="loanDetails.summary">
<h3>Performance History</h3>
<div fxLayout="row" fxLayoutGap="32px" class="performance-history-container">
<p>
Repayments : {{loanDetails?.numberOfRepayments | number}}
</p>
<p>
Maturity Date : {{loanDetails?.timeline.expectedMaturityDate | dateFormat}}
</p>
<table>
<tbody>
<tr>
<td fxFlex="25%">
<b>Number of Repayments :</b>
</td>
<td fxFlex="25%" class="left">
{{loanDetails?.numberOfRepayments | number}}
</td>
<td fxFlex="25%">
<b>Maturity Date :</b>
</td>
<td fxFlex="25%" class="left">
{{loanDetails?.timeline.expectedMaturityDate | dateFormat}}
</td>
</tr>
</tbody>
</table>
</div>
</ng-container>
@@ -10,25 +10,25 @@
<ng-container matColumnDef="days">
<th mat-header-cell class="center" *matHeaderCellDef> Days </th>
<td mat-cell class="center" *matCellDef="let ele"> {{ ele.daysInPeriod }} </td>
<td mat-cell class="center" *matCellDef="let ele" [ngClass]="installmentStyle(ele)"> {{ ele.daysInPeriod }} </td>
<td mat-footer-cell class="center" *matFooterCellDef> <b> Total</b> </td>
</ng-container>
<ng-container matColumnDef="date">
<th mat-header-cell class="center" *matHeaderCellDef> Date </th>
<td mat-cell class="m-r-5" *matCellDef="let ele"> {{ ele.dueDate | dateFormat}} </td>
<td mat-cell class="m-r-5" *matCellDef="let ele" [ngClass]="installmentStyle(ele)"> {{ ele.dueDate | dateFormat}} </td>
<td mat-footer-cell *matFooterCellDef> </td>
</ng-container>
<ng-container matColumnDef="paiddate">
<th mat-header-cell class="center" *matHeaderCellDef> Paid Date </th>
<td mat-cell class="center" *matCellDef="let ele"> {{ ele.obligationsMetOnDate | dateFormat}} </td>
<td mat-cell class="center" *matCellDef="let ele" [ngClass]="installmentStyle(ele)"> {{ ele.obligationsMetOnDate | dateFormat}} </td>
<td mat-footer-cell *matFooterCellDef> </td>
</ng-container>
<ng-container matColumnDef="check">
<th mat-header-cell *matHeaderCellDef> &nbsp; </th>
<td mat-cell class="center" *matCellDef="let ele">
<td mat-cell class="center" *matCellDef="let ele" [ngClass]="installmentStyle(ele)">
<span *ngIf="ele.obligationsMetOnDate"> <i class="fa fa-check"></i> </span>
</td>
<td mat-footer-cell *matFooterCellDef> </td>
@@ -36,62 +36,62 @@
<ng-container matColumnDef="balanceOfLoan">
<th mat-header-cell class="r-amount" *matHeaderCellDef> Balance Of Loan </th>
<td mat-cell class="r-amount" *matCellDef="let ele"> {{ ele.principalLoanBalanceOutstanding | number }} </td>
<td mat-cell class="r-amount" *matCellDef="let ele" [ngClass]="installmentStyle(ele)"> {{ ele.principalLoanBalanceOutstanding | number }} </td>
<td mat-footer-cell class="r-amount" *matFooterCellDef> &nbsp; </td>
</ng-container>
<ng-container matColumnDef="principalDue">
<th mat-header-cell class="r-amount" *matHeaderCellDef> Principal Due </th>
<td mat-cell class="check r-amount" *matCellDef="let ele"> {{ ele.principalDue | number }} </td>
<td mat-cell class="check r-amount" *matCellDef="let ele" [ngClass]="installmentStyle(ele)"> {{ ele.principalDue | number }} </td>
<td mat-footer-cell class="check r-amount" *matFooterCellDef> <b> {{ repaymentScheduleDetails.totalPrincipalExpected | currency }}</b> </td>
</ng-container>
<ng-container matColumnDef="interest">
<th mat-header-cell class="r-amount" *matHeaderCellDef> Interest </th>
<td mat-cell class="r-amount" *matCellDef="let ele"> {{ ele.interestOriginalDue | number}} </td>
<td mat-cell class="r-amount" *matCellDef="let ele" [ngClass]="installmentStyle(ele)"> {{ ele.interestOriginalDue | number}} </td>
<td mat-footer-cell class="r-amount" *matFooterCellDef> <b> {{ repaymentScheduleDetails.totalInterestCharged | currency }} </b> </td>
</ng-container>
<ng-container matColumnDef="fees">
<th mat-header-cell class="r-amount" *matHeaderCellDef> Fees </th>
<td mat-cell class="r-amount" *matCellDef="let ele"> {{ ele.feeChargesDue | number}} </td>
<td mat-cell class="r-amount" *matCellDef="let ele" [ngClass]="installmentStyle(ele)"> {{ ele.feeChargesDue | number}} </td>
<td mat-footer-cell class="r-amount" *matFooterCellDef> <b> {{ repaymentScheduleDetails.totalFeeChargesCharged | currency }} </b> </td>
</ng-container>
<ng-container matColumnDef="penalties">
<th mat-header-cell class="r-amount" *matHeaderCellDef> Penalties </th>
<td mat-cell class="r-amount" *matCellDef="let ele"> {{ ele.penaltyChargesDue | number}} </td>
<td mat-cell class="r-amount" *matCellDef="let ele" [ngClass]="installmentStyle(ele)"> {{ ele.penaltyChargesDue | number}} </td>
<td mat-footer-cell class="r-amount" *matFooterCellDef> <b> {{ repaymentScheduleDetails.totalPenaltyChargesCharged | currency }} </b> </td>
</ng-container>
<ng-container matColumnDef="due">
<th mat-header-cell class="r-amount" *matHeaderCellDef> Due </th>
<td mat-cell class="r-amount" *matCellDef="let ele"> {{ ele.totalDueForPeriod | number}} </td>
<td mat-cell class="r-amount" *matCellDef="let ele" [ngClass]="installmentStyle(ele)"> {{ ele.totalDueForPeriod | number}} </td>
<td mat-footer-cell class="r-amount" *matFooterCellDef> <b> {{ repaymentScheduleDetails.totalRepaymentExpected | currency }} </b> </td>
</ng-container>
<ng-container matColumnDef="paid">
<th mat-header-cell class="r-amount" *matHeaderCellDef> Paid </th>
<td mat-cell class="r-amount" *matCellDef="let ele"> {{ ele.totalPaidForPeriod | number}} </td>
<td mat-cell class="r-amount" *matCellDef="let ele" [ngClass]="installmentStyle(ele)"> {{ ele.totalPaidForPeriod | number}} </td>
<td mat-footer-cell class="r-amount" *matFooterCellDef> <b> {{ repaymentScheduleDetails.totalRepayment | currency }} </b> </td>
</ng-container>
<ng-container matColumnDef="inadvance">
<th mat-header-cell class="r-amount" *matHeaderCellDef> In advance </th>
<td mat-cell class="r-amount" *matCellDef="let ele"> {{ ele.totalPaidInAdvanceForPeriod | number}} </td>
<td mat-cell class="r-amount" *matCellDef="let ele" [ngClass]="installmentStyle(ele)"> {{ ele.totalPaidInAdvanceForPeriod | number}} </td>
<td mat-footer-cell class="r-amount" *matFooterCellDef> <b> {{ repaymentScheduleDetails.totalPaidInAdvance | currency }} </b> </td>
</ng-container>
<ng-container matColumnDef="late">
<th mat-header-cell class="r-amount" *matHeaderCellDef> Late </th>
<td mat-cell class="r-amount" *matCellDef="let ele"> {{ ele.totalPaidLateForPeriod | number}} </td>
<td mat-cell class="r-amount" *matCellDef="let ele" [ngClass]="installmentStyle(ele)"> {{ ele.totalPaidLateForPeriod | number}} </td>
<td mat-footer-cell class="r-amount" *matFooterCellDef> <b> {{ repaymentScheduleDetails.totalPaidLate | currency }} </b> </td>
</ng-container>
<ng-container *ngIf="isWaived">
<ng-container matColumnDef="waived">
<th mat-header-cell class="r-amount" *matHeaderCellDef> Waived </th>
<td mat-cell class="r-amount" *matCellDef="let ele"> {{ ele.totalWaivedForPeriod | number}} </td>
<td mat-cell class="r-amount" *matCellDef="let ele" [ngClass]="installmentStyle(ele)"> {{ ele.totalWaivedForPeriod | number}} </td>
<td mat-footer-cell class="r-amount" *matFooterCellDef> <b> {{ repaymentScheduleDetails.totalWaived | currency }} </b> </td>
</ng-container>
</ng-container>
@@ -17,3 +17,7 @@ table {
.amount-changed {
color: $status-approved;
}
.additional {
color: $status-approved;
}
@@ -41,4 +41,11 @@ export class RepaymentScheduleTabComponent implements OnInit {
this.isWaived = this.repaymentScheduleDetails.totalWaived > 0;
}
installmentStyle(installment: any): string {
if (installment.isAdditional) {
return 'additional';
}
return '';
}
}
@@ -26,21 +26,36 @@
</ng-container>
<ng-container matColumnDef="chargeAppliesTo">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Charge Applies To </th>
<th mat-header-cell *matHeaderCellDef mat-sort-header> Applies To </th>
<td mat-cell *matCellDef="let charge"> {{ charge.chargeAppliesTo.value }} </td>
</ng-container>
<ng-container matColumnDef="chargeTimeType">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Time </th>
<td mat-cell *matCellDef="let charge"> {{ charge.chargeTimeType.value }} </td>
</ng-container>
<ng-container matColumnDef="chargeCalculationType">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Calculation </th>
<td mat-cell *matCellDef="let charge"> {{ charge.chargeCalculationType.value }} </td>
</ng-container>
<ng-container matColumnDef="amount">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Amount </th>
<td mat-cell *matCellDef="let charge" class="r-amount"> {{ charge.amount | number }} </td>
</ng-container>
<ng-container matColumnDef="penalty">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Is Penalty? </th>
<td mat-cell *matCellDef="let charge">
<td mat-cell *matCellDef="let charge" class="center">
<fa-icon *ngIf="charge.penalty" icon="check-circle" size="lg" class="ispenalty" matTooltip="Yes" matTooltipPosition="right"></fa-icon>
<fa-icon *ngIf="!charge.penalty" icon="times-circle" size="lg" class="nopenalty" matTooltip="No" matTooltipPosition="right"></fa-icon>
</td>
</ng-container>
<ng-container matColumnDef="active">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Status </th>
<td mat-cell *matCellDef="let charge">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Is Active? </th>
<td mat-cell *matCellDef="let charge" class="center">
<div [className]="charge.active === true ? 'true' : 'false'">
<fa-icon matTooltip="{{ charge.active === true ? 'Active' : 'Inactive' }}" matTooltipPosition="right" icon="circle" size="lg"></fa-icon>
</div>
@@ -25,7 +25,7 @@ export class ChargesComponent implements OnInit, AfterViewInit {
/** Charge data. */
chargeData: any;
/** Columns to be displayed in charges table. */
displayedColumns: string[] = ['name', 'chargeAppliesTo', 'penalty', 'active'];
displayedColumns: string[] = ['name', 'chargeAppliesTo', 'chargeTimeType', 'chargeCalculationType', 'amount', 'penalty', 'active'];
/** Data source for charges table. */
dataSource: MatTableDataSource<any>;
@@ -86,6 +86,17 @@
</mat-checkbox>
</div>
<mat-form-field *ngIf="chargeForm.controls.chargeTimeType.value === 9 && chargeForm.controls.addFeeFrequency.value" fxFlex="48%">
<mat-label>Frequency Interval</mat-label>
<input matInput required formControlName="feeInterval">
<mat-error *ngIf="chargeForm.controls.feeInterval.hasError('required')">
Frequency Interval is <strong>required</strong>
</mat-error>
<mat-error *ngIf="chargeForm.controls.feeInterval.hasError('pattern')">
Frequency Interval <strong>must be a positive integer</strong>
</mat-error>
</mat-form-field>
<mat-form-field *ngIf="chargeForm.controls.chargeTimeType.value === 9 && chargeForm.controls.addFeeFrequency.value" fxFlex="48%">
<mat-label>Charge Frequency</mat-label>
<mat-select required formControlName="feeFrequency">
@@ -98,17 +109,6 @@
</mat-error>
</mat-form-field>
<mat-form-field *ngIf="chargeForm.controls.chargeTimeType.value === 9 && chargeForm.controls.addFeeFrequency.value" fxFlex="48%">
<mat-label>Frequency Interval</mat-label>
<input matInput required formControlName="feeInterval">
<mat-error *ngIf="chargeForm.controls.feeInterval.hasError('required')">
Frequency Interval is <strong>required</strong>
</mat-error>
<mat-error *ngIf="chargeForm.controls.feeInterval.hasError('pattern')">
Frequency Interval <strong>must be a positive integer</strong>
</mat-error>
</mat-form-field>
<mat-form-field (click)="dueDatePicker.open()" *ngIf="chargeForm.controls.chargeTimeType.value === 6 || chargeForm.controls.chargeTimeType.value === 7" fxFlex="48%">
<mat-label>Due Date</mat-label>
<input matInput [min]="minDate" [max]="maxDate" [matDatepicker]="dueDatePicker" required formControlName="feeOnMonthDay">
@@ -178,7 +178,7 @@
{{ incomeOrLiabilityAccount.name }}
</mat-option>
</mat-select>
</mat-form-field>
</mat-form-field>
<mat-form-field fxFlex="48%">
<mat-label>Tax Group</mat-label>
@@ -18,7 +18,7 @@
</mat-form-field>
</div>
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" style="margin-top:10px;">
<mat-form-field fxFlex="48%">
@@ -28,7 +28,7 @@
Name <strong>is required</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="48%">
<mat-label>Currency</mat-label>
<mat-select required formControlName="currencyCode">
@@ -41,7 +41,7 @@
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="48%">
<mat-label>Charge time type</mat-label>
<mat-select required formControlName="chargeTimeType">
@@ -52,9 +52,9 @@
<mat-error *ngIf="chargeForm.controls.chargeTimeType.hasError('required')">
Charge Time Type is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="48%">
<mat-label>Charge calculation</mat-label>
<mat-select required formControlName="chargeCalculationType">
@@ -78,7 +78,7 @@
Charge Payment Mode is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="48%">
<mat-label>Amount</mat-label>
<input matInput required autofocus type="text" formControlName="amount">
@@ -86,7 +86,7 @@
Amount <strong>is required</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="48%" *ngIf="showGLAccount">
<mat-label>Income from charge</mat-label>
<mat-select required formControlName="incomeAccountId">
@@ -98,7 +98,7 @@
Income from charge is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="48%">
<mat-label>Tax Group</mat-label>
<mat-select *ngIf="chargeData.taxGroup" required formControlName="taxGroupId">
@@ -114,12 +114,20 @@
</mat-select>
</mat-form-field>
<div fxFlex="48%" class="password-never-expires-wrapper" *ngIf="addFeeFrequency" style="padding-top: 10px;">
<mat-checkbox labelPosition="before" (change)="getFeeFrequency($event.checked)">
<div fxFlex="48%" class="password-never-expires-wrapper checkbox" *ngIf="addFeeFrequency">
<mat-checkbox labelPosition="before" [checked]="addFeeFrequency && showFeeOptions" (change)="getFeeFrequency($event.checked)">
Add Fee Frequency
</mat-checkbox>
</div>
<mat-form-field fxFlex="48%" *ngIf="addFeeFrequency && showFeeOptions">
<mat-label>Frequency Interval</mat-label>
<input matInput required autofocus type="text" formControlName="feeInterval">
<mat-error *ngIf="chargeForm.controls.feeInterval.hasError('required')">
Frequency Interval <strong>is required</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="48%" *ngIf="addFeeFrequency && showFeeOptions">
<mat-label>Charge Frequency</mat-label>
<mat-select required formControlName="feeFrequency">
@@ -128,19 +136,10 @@
</mat-option>
</mat-select>
<mat-error *ngIf="chargeForm.controls.feeFrequency.hasError('required')">
Fee Frequency is <strong>required</strong>
Fee Frequency <strong>is required</strong>
</mat-error>
</mat-form-field>
<mat-form-field fxFlex="48%" *ngIf="addFeeFrequency && showFeeOptions">
<mat-label>Frequency Interval</mat-label>
<input matInput required autofocus type="text" formControlName="feeInterval" required>
<mat-error *ngIf="chargeForm.controls.feeInterval.hasError('required')">
Amount <strong>is required</strong>
</mat-error>
</mat-form-field>
</div>
<div fxLayout="row wrap" fxLayoutGap="2%" fxLayout.lt-md="column" style="margin-top:10px;">
@@ -149,7 +148,7 @@
Active
</mat-checkbox>
</div>
<div fxFlex="48%" class="send-password-to-email-wrapper" *ngIf="showPenalty">
<mat-checkbox labelPosition="before" formControlName="penalty">
Is Penalty
@@ -0,0 +1,3 @@
.checkbox {
padding-top: 10px;
}
@@ -71,6 +71,8 @@ export class EditChargeComponent implements OnInit {
* Edit Charge form.
*/
editChargeForm() {
this.showFeeOptions = (this.chargeData.feeInterval && this.chargeData.feeInterval > 0);
this.chargeForm = this.formBuilder.group({
'name': [this.chargeData.name, Validators.required],
'chargeAppliesTo': [{ value: this.chargeData.chargeAppliesTo.id, disabled: true }, Validators.required],
@@ -88,6 +90,13 @@ export class EditChargeComponent implements OnInit {
this.addFeeFrequency = true;
this.chargePaymentMode = true;
this.chargeForm.addControl('chargePaymentMode', this.formBuilder.control(this.chargeData.chargePaymentMode.id, Validators.required));
if (this.showFeeOptions) {
this.getFeeFrequency(this.showFeeOptions);
this.chargeForm.patchValue({
'feeInterval': this.chargeData.feeInterval,
'feeFrequency': this.chargeData.feeFrequency.id
});
}
break;
}
case 'Savings': {
@@ -123,6 +123,9 @@
</div>
<div fxLayout="row" fxLayoutAlign="center" fxLayoutGap="2%" fxLayout.lt-md="column">
<button type="button" mat-raised-button color="primary" [routerLink]="['../']">{{ 'Back' | translate }}</button>
</div>
</mat-card-content>
</mat-card>
+1 -1
View File
@@ -772,7 +772,7 @@ const routes: Routes = [
},
{
path: ':id',
data: { title: extract('View Charges'), routeParamBreadcrumb: 'id' },
data: { title: extract('View Charges'), breadcrumb: 'id', routeParamBreadcrumb: 'id' },
resolve: {
charge: ChargeResolver
},
+4
View File
@@ -22,6 +22,10 @@
padding-right: 5px !important;
}
.left {
text-align: left !important;
}
.right {
text-align: right !important;
}