feat: create, view, edit for floating rates (#402)

- Add floating-rates
- Add create-floating-rate
- Add view-floating-rate
- Add edit-floating-rate

#194 #187
This commit is contained in:
Chirag Gupta
2020-03-22 18:32:19 +05:30
committed by GitHub
parent 51d622a9ff
commit 85b8e907f8
26 changed files with 1281 additions and 3 deletions
@@ -0,0 +1,100 @@
<div class="container">
<mat-card>
<form [formGroup]="floatingRateForm" (ngSubmit)="submit()">
<mat-card-content>
<div fxLayout="row wrap" fxLayout.lt-md="column" fxLayoutGap="4%">
<mat-form-field fxFlex="30%">
<mat-label>Floating Rate Name</mat-label>
<input matInput required formControlName="name">
<mat-error *ngIf="floatingRateForm.controls.name.hasError('required')">
Floating Rate Name is <strong>required</strong>
</mat-error>
</mat-form-field>
<div class="checkbox-wrapper" fxFlex="30%">
<mat-checkbox formControlName="isBaseLendingRate" class="checkbox" labelPosition="before">Is Base Lending
Rate?</mat-checkbox>
</div>
<div class="checkbox-wrapper" fxFlex="30%">
<mat-checkbox formControlName="isActive" class="checkbox" labelPosition="before">Active</mat-checkbox>
</div>
</div>
<br>
<mat-divider [inset]="true"></mat-divider>
<br>
<div fxLayout="row wrap" fxLayoutGap="70%" fxLayoutGap.lt-md="0px" class="m-b-10" fxLayout.lt-md="column">
<p fxFlex="25%" class="mat-title">Floating Rate Periods</p>
<button mat-mini-fab type="button" color="primary" (click)="addFloatingRatePeriod()">
<fa-icon icon="plus"></fa-icon>
</button>
</div>
<table mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="fromDate">
<th mat-header-cell *matHeaderCellDef mat-sort-header> From Date </th>
<td mat-cell *matCellDef="let floatingRatePeriod"> {{ floatingRatePeriod.fromDate | date : 'dd MMMM yyyy' }} </td>
</ng-container>
<ng-container matColumnDef="interestRate">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Interest Rate </th>
<td mat-cell *matCellDef="let floatingRatePeriod"> {{ floatingRatePeriod.interestRate }} </td>
</ng-container>
<ng-container matColumnDef="isDifferential">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Is Differential? </th>
<td mat-cell *matCellDef="let floatingRate">
<fa-icon *ngIf="floatingRate.isDifferentialToBaseLendingRate" icon="check-circle" size="lg"
class="is-differential" matTooltip="Yes" matTooltipPosition="right"></fa-icon>
<fa-icon *ngIf="!floatingRate.isDifferentialToBaseLendingRate" icon="times-circle" size="lg"
class="not-is-differential" matTooltip="No" matTooltipPosition="right"></fa-icon>
</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> Actions </th>
<td mat-cell *matCellDef="let floatingRatePeriod" fxLayoutGap="15%">
<button type="button" fxFlex="8%" color="primary" mat-icon-button
(click)="editFloatingRatePeriod(floatingRatePeriod)">
<fa-icon icon="edit" size="lg"></fa-icon>
</button>
<button type="button" fxFlex="8%" color="warn" mat-icon-button
(click)="deleteFloatingRatePeriod(floatingRatePeriod)">
<fa-icon icon="trash" size="lg"></fa-icon>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSizeOptions]="[10, 25, 50, 100]" showFirstLastButtons></mat-paginator>
</mat-card-content>
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
<button mat-raised-button type="submit" color="primary" [disabled]="!floatingRateForm.valid">Submit</button>
</mat-card-actions>
</form>
</mat-card>
</div>
@@ -0,0 +1,26 @@
@media (min-width: 992px) {
.checkbox-wrapper {
position: relative;
.checkbox {
padding: 0 0 17.5px 0;
position: absolute;
bottom: 0;
}
}
}
// TODO: CONFIGURE THESE CLASSES GLOBALLY
.is-differential {
color: #32cd32;
}
.not-is-differential {
color: #f44366;
}
table {
width: 100%;
}
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { CreateFloatingRateComponent } from './create-floating-rate.component';
describe('CreateFloatingRateComponent', () => {
let component: CreateFloatingRateComponent;
let fixture: ComponentFixture<CreateFloatingRateComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ CreateFloatingRateComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(CreateFloatingRateComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,173 @@
/** Angular Imports */
import { Component, OnInit, ViewChild } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { FormBuilder, FormGroup, Validators, FormArray } from '@angular/forms';
import { DatePipe } from '@angular/common';
import { MatTableDataSource, MatPaginator, MatSort, MatDialog } from '@angular/material';
/** Custom Services */
import { ProductsService } from '../../products.service';
/** Custom Components */
import { FloatingRatePeriodDialogComponent } from '../floating-rate-period-dialog/floating-rate-period-dialog.component';
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
/**
* Create Floating Rate Component.
*/
@Component({
selector: 'mifosx-create-floating-rate',
templateUrl: './create-floating-rate.component.html',
styleUrls: ['./create-floating-rate.component.scss']
})
export class CreateFloatingRateComponent implements OnInit {
/** Floating Rate Period Data. */
floatingRatePeriodsData: any[] = [];
/** Minimum floating rate period date allowed. */
minDate = new Date();
/** Floating Rate Form. */
floatingRateForm: FormGroup;
/** Columns to be displayed in floating rate periods table. */
displayedColumns: string[] = ['fromDate', 'interestRate', 'isDifferential', 'actions'];
/** Data source for floating rate periods table. */
dataSource: MatTableDataSource<any>;
/** Date Format. */
dateFormat = 'dd MMMM yyyy';
/** Paginator for floating rate periods table. */
@ViewChild(MatPaginator) paginator: MatPaginator;
/** Sorter for floating rate periods table. */
@ViewChild(MatSort) sort: MatSort;
/**
* @param {Router} router Router for navigation.
* @param {FormBuilder} formBuilder Form Builder.
* @param {ProductsService} productsService Product Service.
* @param {ActivatedRoute} route Activated Route.
* @param {DatePipe} datePipe Date Pipe.
* @param {MatDialog} dialog Dialog reference.
*/
constructor(private router: Router,
private formBuilder: FormBuilder,
private productsService: ProductsService,
private route: ActivatedRoute,
private datePipe: DatePipe,
private dialog: MatDialog) { }
/**
* Sets the floating rate periods table.
*/
ngOnInit() {
this.setFloatingRates();
this.createFloatingRateForm();
}
/**
* Creates the floating rate form.
*/
createFloatingRateForm() {
this.floatingRateForm = this.formBuilder.group({
'name': ['', Validators.required],
'isBaseLendingRate': [false],
'isActive': [false]
});
}
/**
* Initializes the data source, paginator and sorter for floating rate periods table.
*/
setFloatingRates() {
this.dataSource = new MatTableDataSource(this.floatingRatePeriodsData);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
/**
* Creates the Floating Rate Periods Form.
* @returns {FormGroup} Floating Rate Period Form.
*/
createFloatingRatePeriodsForm(): FormGroup {
return this.formBuilder.group({
'fromDate': ['', Validators.required],
'interestRate': ['', Validators.required],
'isDifferentialToBaseLendingRate': [false]
});
}
/**
* Adds a new floating rate period.
*/
addFloatingRatePeriod() {
const floatingRatePeriodDialogRef = this.dialog.open(FloatingRatePeriodDialogComponent, {
data: {}
});
floatingRatePeriodDialogRef.afterClosed().subscribe((response: any) => {
if (response) {
this.floatingRatePeriodsData.push({
fromDate: this.datePipe.transform(response.fromDate, this.dateFormat),
interestRate: response.interestRate,
isDifferentialToBaseLendingRate: response.isDifferentialToBaseLendingRate,
locale: 'en',
dateFormat: this.dateFormat
});
this.dataSource.connect().next(this.floatingRatePeriodsData);
}
});
}
/**
* Edits floating rate period.
* @param {any} ratePeriod Floating Rate Period.
*/
editFloatingRatePeriod(ratePeriod: any) {
const editFloatingRatePeriodDialogRef = this.dialog.open(FloatingRatePeriodDialogComponent, {
data: {
fromDate: ratePeriod.fromDate,
interestRate: ratePeriod.interestRate,
isDifferentialToBaseLendingRate: ratePeriod.isDifferentialToBaseLendingRate
}
});
editFloatingRatePeriodDialogRef.afterClosed().subscribe((response: any) => {
if (response) {
this.floatingRatePeriodsData[this.floatingRatePeriodsData.indexOf(ratePeriod)] = {
fromDate: this.datePipe.transform(response.fromDate, this.dateFormat),
interestRate: response.interestRate,
isDifferentialToBaseLendingRate: response.isDifferentialToBaseLendingRate,
locale: 'en',
dateFormat: this.dateFormat
};
this.dataSource.connect().next(this.floatingRatePeriodsData);
}
});
}
/**
* Deletes the floating rate period.
* @param {any} ratePeriod Floating Rate Period.
*/
deleteFloatingRatePeriod(ratePeriod: any) {
const deleteFloatingRatePeriodRef = this.dialog.open(DeleteDialogComponent, {
data: { deleteContext: `floating rate period with from date as ${ratePeriod.fromDate}` }
});
deleteFloatingRatePeriodRef.afterClosed().subscribe((response: any) => {
if (response.delete) {
this.floatingRatePeriodsData.splice(this.floatingRatePeriodsData.indexOf(ratePeriod), 1);
this.dataSource.connect().next(this.floatingRatePeriodsData);
}
});
}
/**
* Submits the floating rate form and creates floating rate,
* if successful redirects to view created floating rate.
*/
submit() {
this.floatingRateForm.value.ratePeriods = this.floatingRatePeriodsData;
this.productsService.createFloatingRate(this.floatingRateForm.value)
.subscribe((response: any) => {
this.router.navigate(['../', response.resourceId], { relativeTo: this.route });
});
}
}
@@ -0,0 +1,105 @@
<div class="container">
<mat-card>
<form [formGroup]="floatingRateForm" (ngSubmit)="submit()">
<mat-card-content>
<div fxLayout="row wrap" fxLayout.lt-md="column" fxLayoutGap="15%">
<mat-form-field fxFlex="25%">
<mat-label>Floating Rate Name</mat-label>
<input matInput required formControlName="name">
<mat-error *ngIf="floatingRateForm.controls.name.hasError('required')">
Floating Rate Name is <strong>required</strong>
</mat-error>
</mat-form-field>
<div class="checkbox-wrapper" fxFlex="25%">
<mat-checkbox formControlName="isBaseLendingRate" class="checkbox" labelPosition="before">
Is Base Lending Rate?
</mat-checkbox>
</div>
<div class="checkbox-wrapper" fxFlex="15%">
<mat-checkbox formControlName="isActive" class="checkbox" labelPosition="before">
Active
</mat-checkbox>
</div>
</div>
<br>
<mat-divider [inset]="true"></mat-divider>
<br>
<div fxLayout="row wrap" fxLayoutGap="70%" fxLayoutGap.lt-md="0px" class="m-b-10" fxLayout.lt-md="column">
<p fxFlex="25%" class="mat-title">Floating Rate Periods</p>
<button mat-mini-fab type="button" color="primary" (click)="addFloatingRatePeriod()">
<fa-icon icon="plus"></fa-icon>
</button>
</div>
<table mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="fromDate">
<th mat-header-cell *matHeaderCellDef mat-sort-header> From Date </th>
<td mat-cell *matCellDef="let floatingRatePeriod"> {{ floatingRatePeriod.fromDate | date : 'dd MMMM yyyy' }} </td>
</ng-container>
<ng-container matColumnDef="interestRate">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Interest Rate </th>
<td mat-cell *matCellDef="let floatingRatePeriod"> {{ floatingRatePeriod.interestRate }} </td>
</ng-container>
<ng-container matColumnDef="isDifferential">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Is Differential? </th>
<td mat-cell *matCellDef="let floatingRate">
<fa-icon *ngIf="floatingRate.isDifferentialToBaseLendingRate" icon="check-circle" size="lg"
class="is-differential" matTooltip="Yes" matTooltipPosition="right"></fa-icon>
<fa-icon *ngIf="!floatingRate.isDifferentialToBaseLendingRate" icon="times-circle" size="lg"
class="not-is-differential" matTooltip="No" matTooltipPosition="right"></fa-icon>
</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> Actions </th>
<td mat-cell *matCellDef="let floatingRatePeriod">
<button type="button" color="primary" mat-icon-button
(click)="editFloatingRatePeriod(floatingRatePeriod)">
<fa-icon icon="edit" size="lg"></fa-icon>
</button>
<button type="button" color="warn" mat-icon-button
(click)="deleteFloatingRatePeriod(floatingRatePeriod)">
<fa-icon icon="trash" size="lg"></fa-icon>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSizeOptions]="[10, 25, 50, 100]" showFirstLastButtons></mat-paginator>
</mat-card-content>
<mat-card-actions fxLayout="row" fxLayout.xs="column" fxLayoutAlign="center" fxLayoutGap="5px">
<button type="button" mat-raised-button [routerLink]="['../']">Cancel</button>
<button mat-raised-button type="submit" color="primary" [disabled]="!floatingRateForm.valid || floatingRateForm.pristine && isFloatingRateFormPristine">
Submit
</button>
</mat-card-actions>
</form>
</mat-card>
</div>
@@ -0,0 +1,26 @@
@media (min-width: 992px) {
.checkbox-wrapper {
position: relative;
.checkbox {
padding: 0 0 17.5px 0;
position: absolute;
bottom: 0;
}
}
}
// TODO: CONFIGURE THESE CLASSES GLOBALLY
.is-differential {
color: #32cd32;
}
.not-is-differential {
color: #f44366;
}
table {
width: 100%;
}
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { EditFloatingRateComponent } from './edit-floating-rate.component';
describe('EditFloatingRateComponent', () => {
let component: EditFloatingRateComponent;
let fixture: ComponentFixture<EditFloatingRateComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ EditFloatingRateComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(EditFloatingRateComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,185 @@
/** Angular Imports */
import { Component, OnInit, ViewChild } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { FormBuilder, FormGroup, Validators, FormArray } from '@angular/forms';
import { DatePipe } from '@angular/common';
import { MatTableDataSource, MatPaginator, MatSort, MatDialog } from '@angular/material';
/** Custom Services */
import { ProductsService } from '../../products.service';
/** Custom Components */
import { FloatingRatePeriodDialogComponent } from '../floating-rate-period-dialog/floating-rate-period-dialog.component';
import { DeleteDialogComponent } from 'app/shared/delete-dialog/delete-dialog.component';
/**
* Edit Floating Rate Component.
*/
@Component({
selector: 'mifosx-edit-floating-rate',
templateUrl: './edit-floating-rate.component.html',
styleUrls: ['./edit-floating-rate.component.scss']
})
export class EditFloatingRateComponent implements OnInit {
/** Floating Rate Form. */
floatingRateForm: FormGroup;
/** Floating Rate Data. */
floatingRateData: any;
/** Minimum floating rate period date allowed. */
minDate = new Date();
/** Form Pristine Status. */
isFloatingRateFormPristine = true;
/** Columns to be displayed in floating rate periods table. */
displayedColumns: string[] = ['fromDate', 'interestRate', 'isDifferential', 'actions'];
/** Data source for floating rate periods table. */
dataSource: MatTableDataSource<any>;
/** Date Format. */
dateFormat = 'dd MMMM yyyy';
/** Floating Rate Period Data. */
floatingRatePeriodsData: any[] = [];
/** Paginator for floating rate periods table. */
@ViewChild(MatPaginator) paginator: MatPaginator;
/** Sorter for floating rate periods table. */
@ViewChild(MatSort) sort: MatSort;
/**
* Retrieves the floating rate data from `resolve`.
* @param {Router} router Router for navigation.
* @param {FormBuilder} formBuilder Form Builder.
* @param {ProductsService} productsService Product Service.
* @param {ActivatedRoute} route Activated Route.
* @param {DatePipe} datePipe Date Pipe.
* @param {MatDialog} dialog Dialog reference.
*/
constructor(private router: Router,
private formBuilder: FormBuilder,
private productsService: ProductsService,
private route: ActivatedRoute,
private datePipe: DatePipe,
private dialog: MatDialog) {
this.route.data.subscribe((data: { floatingRate: any }) => {
this.floatingRateData = data.floatingRate;
this.floatingRatePeriodsData = data.floatingRate.ratePeriods ? data.floatingRate.ratePeriods : [];
});
}
/**
* Sets the floating rate periods table.
*/
ngOnInit() {
this.createFloatingRateForm();
this.setFloatingRates();
}
/**
* Creates and sets the Floating Rate Form.
*/
createFloatingRateForm() {
this.floatingRateForm = this.formBuilder.group({
'name': [this.floatingRateData.name, Validators.required],
'isBaseLendingRate': [this.floatingRateData.isBaseLendingRate],
'isActive': [this.floatingRateData.isActive]
});
}
/**
* Initializes the data source, paginator and sorter for floating rate periods table.
*/
setFloatingRates() {
this.dataSource = new MatTableDataSource(this.floatingRatePeriodsData);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
/**
* Adds a new floating rate period.
*/
addFloatingRatePeriod() {
const floatingRatePeriodDialogRef = this.dialog.open(FloatingRatePeriodDialogComponent, {
data: {}
});
floatingRatePeriodDialogRef.afterClosed().subscribe((response: any) => {
if (response) {
this.floatingRatePeriodsData.push({
fromDate: this.datePipe.transform(response.fromDate, this.dateFormat),
interestRate: response.interestRate,
isDifferentialToBaseLendingRate: response.isDifferentialToBaseLendingRate,
locale: 'en',
dateFormat: this.dateFormat
});
this.dataSource.connect().next(this.floatingRatePeriodsData);
this.isFloatingRateFormPristine = false;
}
});
}
/**
* Edits floating rate period.
* @param {any} ratePeriod Floating Rate Period.
*/
editFloatingRatePeriod(ratePeriod: any) {
const editFloatingRatePeriodDialogRef = this.dialog.open(FloatingRatePeriodDialogComponent, {
data: {
fromDate: ratePeriod.fromDate,
interestRate: ratePeriod.interestRate,
isDifferentialToBaseLendingRate: ratePeriod.isDifferentialToBaseLendingRate
}
});
editFloatingRatePeriodDialogRef.afterClosed().subscribe((response: any) => {
if (response) {
this.floatingRatePeriodsData[this.floatingRatePeriodsData.indexOf(ratePeriod)] = {
fromDate: this.datePipe.transform(response.fromDate, this.dateFormat),
interestRate: response.interestRate,
isDifferentialToBaseLendingRate: response.isDifferentialToBaseLendingRate,
locale: 'en',
dateFormat: this.dateFormat
};
this.dataSource.connect().next(this.floatingRatePeriodsData);
this.isFloatingRateFormPristine = false;
}
});
}
/**
* Deletes the floating rate period.
* @param {any} ratePeriod Floating Rate Period.
*/
deleteFloatingRatePeriod(ratePeriod: any) {
const deleteFloatingRatePeriodRef = this.dialog.open(DeleteDialogComponent, {
data: { deleteContext: `floating rate period with from date as ${ratePeriod.fromDate}` }
});
deleteFloatingRatePeriodRef.afterClosed().subscribe((response: any) => {
if (response.delete) {
this.floatingRatePeriodsData.splice(this.floatingRatePeriodsData.indexOf(ratePeriod), 1);
this.dataSource.connect().next(this.floatingRatePeriodsData);
this.isFloatingRateFormPristine = false;
}
});
}
/**
* Submits the floating rate form and creates floating rate,
* if successful redirects to view created floating rate.
*/
submit() {
this.floatingRatePeriodsData.map(floatingRatePeriod => {
floatingRatePeriod.modifiedOn = undefined;
floatingRatePeriod.createdOn = undefined;
floatingRatePeriod.id = undefined;
floatingRatePeriod.modifiedBy = undefined;
floatingRatePeriod.createdBy = undefined;
floatingRatePeriod.isActive = undefined;
floatingRatePeriod.locale = 'en';
floatingRatePeriod.dateFormat = this.dateFormat;
floatingRatePeriod.fromDate = this.datePipe.transform(floatingRatePeriod.fromDate, this.dateFormat);
});
this.floatingRateForm.value.ratePeriods = this.floatingRatePeriodsData.length > 0 ? this.floatingRatePeriodsData : undefined;
this.productsService.updateFloatingRate(this.route.snapshot.paramMap.get('id'), this.floatingRateForm.value)
.subscribe((response: any) => {
this.router.navigate(['../../', response.resourceId], { relativeTo: this.route });
});
}
}
@@ -0,0 +1,41 @@
<h1 mat-dialog-title>Floating Rate Period</h1>
<mat-dialog-content>
<form [formGroup]="floatingRatePeriodForm">
<div fxLayout="column">
<mat-form-field>
<mat-label>From Date</mat-label>
<input required matInput formControlName="fromDate" [min]="minDate" [matDatepicker]="fromDatePicker">
<mat-datepicker-toggle matSuffix [for]="fromDatePicker"></mat-datepicker-toggle>
<mat-datepicker #fromDatePicker></mat-datepicker>
<mat-error *ngIf="floatingRatePeriodForm.controls.fromDate.hasError('required')">
From Date is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-form-field>
<mat-label>Interest Rate</mat-label>
<input matInput type="number" required formControlName="interestRate">
<mat-error *ngIf="floatingRatePeriodForm.controls.interestRate.hasError('required')">
Interest Rate is <strong>required</strong>
</mat-error>
</mat-form-field>
<mat-checkbox class="is-differential" formControlName="isDifferentialToBaseLendingRate" labelPosition="before">
Is Differential?
</mat-checkbox>
</div>
</form>
</mat-dialog-content>
<mat-dialog-actions align="end">
<button mat-button mat-dialog-close>Cancel</button>
<button mat-raised-button color="primary"
[disabled]="!floatingRatePeriodForm.valid || floatingRatePeriodForm.pristine" (click)="submit()">Submit</button>
</mat-dialog-actions>
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { FloatingRatePeriodDialogComponent } from './floating-rate-period-dialog.component';
describe('FloatingRatePeriodDialogComponent', () => {
let component: FloatingRatePeriodDialogComponent;
let fixture: ComponentFixture<FloatingRatePeriodDialogComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ FloatingRatePeriodDialogComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(FloatingRatePeriodDialogComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,50 @@
/** Angular Imports */
import { Component, OnInit, Inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';
/**
* Floating Rate Period Dialog Component.
*/
@Component({
selector: 'mifosx-floating-rate-period-dialog',
templateUrl: './floating-rate-period-dialog.component.html',
styleUrls: ['./floating-rate-period-dialog.component.scss']
})
export class FloatingRatePeriodDialogComponent implements OnInit {
/** Floating Rate Period Form. */
floatingRatePeriodForm: FormGroup;
/** Minimum floating rate period date allowed. */
minDate = new Date();
/**
* @param {MatDialogRef} dialogRef Component reference to dialog.
* @param {FormBuilder} formBuilder Form Builder.
* @param {any} data Provides values for the form (if available).
*/
constructor(public dialogRef: MatDialogRef<FloatingRatePeriodDialogComponent>,
public formBuilder: FormBuilder,
@Inject(MAT_DIALOG_DATA) public data: any) {
}
/**
* Creates the floating rate period form.
*/
ngOnInit() {
const rowDisabled: Boolean = this.data ? (new Date(this.data.fromDate) < new Date() ? true : false) : false;
this.floatingRatePeriodForm = this.formBuilder.group({
'fromDate': [{ value: this.data ? new Date(this.data.fromDate) : '', disabled: rowDisabled }, Validators.required],
'interestRate': [{ value: this.data ? this.data.interestRate : '', disabled: rowDisabled }, Validators.required],
'isDifferentialToBaseLendingRate': [{ value: this.data ? this.data.isDifferentialToBaseLendingRate : false, disabled: rowDisabled }]
});
}
/**
* Closes the dialog and returns value of the form.
*/
submit() {
this.dialogRef.close(this.floatingRatePeriodForm.value);
}
}
@@ -0,0 +1,31 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
import { Observable } from 'rxjs';
/** Custom Services */
import { ProductsService } from '../products.service';
/**
* Floating Rate data resolver.
*/
@Injectable()
export class FloatingRateResolver implements Resolve<Object> {
/**
* @param {ProductsService} productsService Products service.
*/
constructor(private productsService: ProductsService) {}
/**
* Returns the floating rate data.
* @returns {Observable<any>}
*/
resolve(route: ActivatedRouteSnapshot): Observable<any> {
const floatingRateId = route.paramMap.get('id');
return this.productsService.getFloatingRate(floatingRateId);
}
}
@@ -0,0 +1,56 @@
<div class="container m-b-20" fxLayout="row" fxLayoutAlign="end" fxLayoutGap="20px">
<button mat-raised-button color="primary" [routerLink]="['create']">
<fa-icon icon="plus"></fa-icon>&nbsp;&nbsp;
Create Floating Rate
</button>
</div>
<div class="container">
<div fxLayout="row" fxLayoutGap="20px">
<mat-form-field fxFlex>
<mat-label>Filter</mat-label>
<input matInput (keyup)="applyFilter($event.target.value)">
</mat-form-field>
</div>
<div class="mat-elevation-z8">
<table mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Name </th>
<td mat-cell *matCellDef="let floatingRate"> {{ floatingRate.name }} </td>
</ng-container>
<ng-container matColumnDef="createdBy">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Created By </th>
<td mat-cell *matCellDef="let floatingRate"> {{ floatingRate.createdBy }} </td>
</ng-container>
<ng-container matColumnDef="isBaseLendingRate">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Is base lending rate? </th>
<td mat-cell *matCellDef="let floatingRate">
<fa-icon *ngIf="floatingRate.isBaseLendingRate" icon="check-circle" size="lg" class="is-base-lending-rate-or-active" matTooltip="Yes" matTooltipPosition="right"></fa-icon>
<fa-icon *ngIf="!floatingRate.isBaseLendingRate" icon="times-circle" size="lg" class="not-is-base-lending-rate-or-active" matTooltip="No" matTooltipPosition="right"></fa-icon>
</td>
</ng-container>
<ng-container matColumnDef="isActive">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Active </th>
<td mat-cell *matCellDef="let floatingRate">
<fa-icon *ngIf="floatingRate.isActive" icon="check-circle" size="lg" class="is-base-lending-rate-or-active" matTooltip="Yes" matTooltipPosition="right"></fa-icon>
<fa-icon *ngIf="!floatingRate.isActive" icon="times-circle" size="lg" class="not-is-base-lending-rate-or-active" matTooltip="No" matTooltipPosition="right"></fa-icon>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" class="select-row" [routerLink]="[row.id]"></tr>
</table>
<mat-paginator [pageSizeOptions]="[10, 25, 50, 100]" showFirstLastButtons></mat-paginator>
</div>
</div>
@@ -0,0 +1,16 @@
table {
width: 100%;
.select-row:hover {
cursor: pointer;
}
}
// TODO: CONFIGURE THESE CLASSES GLOBALLY
.is-base-lending-rate-or-active {
color: #32cd32;
}
.not-is-base-lending-rate-or-active {
color: #f44366;
}
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { FloatingRatesComponent } from './floating-rates.component';
describe('FloatingRatesComponent', () => {
let component: FloatingRatesComponent;
let fixture: ComponentFixture<FloatingRatesComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ FloatingRatesComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(FloatingRatesComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,62 @@
/** Angular Imports */
import { Component, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { MatTableDataSource, MatPaginator, MatSort } from '@angular/material';
/**
* Floating Rates Component.
*/
@Component({
selector: 'mifosx-floating-rates',
templateUrl: './floating-rates.component.html',
styleUrls: ['./floating-rates.component.scss']
})
export class FloatingRatesComponent implements OnInit {
/** Floating Rates data. */
floatingRatesData: any;
/** Columns to be displayed in floating rates table. */
displayedColumns: string[] = ['name', 'createdBy', 'isBaseLendingRate', 'isActive'];
/** Data source for floating rates table. */
dataSource: MatTableDataSource<any>;
/** Paginator for floating rates table. */
@ViewChild(MatPaginator) paginator: MatPaginator;
/** Sorter for floating rates table. */
@ViewChild(MatSort) sort: MatSort;
/**
* Retrieves the floating rates data from `resolve`.
* @param {ActivatedRoute} route Activated Route.
*/
constructor(private route: ActivatedRoute) {
this.route.data.subscribe(( data: { floatingrates: any } ) => {
this.floatingRatesData = data.floatingrates;
});
}
/**
* Filters data in floating rates table based on passed value.
* @param {string} filterValue Value to filter data.
*/
applyFilter(filterValue: string) {
this.dataSource.filter = filterValue.trim().toLowerCase();
}
/**
* Sets the floating rates table.
*/
ngOnInit() {
this.setFloatingRates();
}
/**
* Initializes the data source, paginator and sorter for floating rates table.
*/
setFloatingRates() {
this.dataSource = new MatTableDataSource(this.floatingRatesData);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
}
@@ -0,0 +1,30 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Resolve } from '@angular/router';
/** rxjs Imports */
import { Observable } from 'rxjs';
/** Custom Services */
import { ProductsService } from '../products.service';
/**
* Floating Rates data resolver.
*/
@Injectable()
export class FloatingRatesResolver implements Resolve<Object> {
/**
* @param {ProductsService} productsService Products service.
*/
constructor(private productsService: ProductsService) {}
/**
* Returns the floating rates data.
* @returns {Observable<any>}
*/
resolve(): Observable<any> {
return this.productsService.getFloatingRates();
}
}
@@ -0,0 +1,89 @@
<div class="container m-b-20" fxLayout="row" fxLayoutAlign="end" fxLayoutGap="20px">
<button mat-raised-button color="primary" [routerLink]="['edit']">
<fa-icon icon="edit"></fa-icon>&nbsp;&nbsp;
Edit
</button>
</div>
<div class="container">
<mat-card>
<mat-card-content>
<div fxLayout="row wrap" class="content" fxLayout.lt-md="column">
<div fxFlex="18%" class="mat-body-strong">
Floating Rate Name:
</div>
<div fxFlex="18%">
{{ floatingRateData.name }}
</div>
<div fxFlex="20%" class="mat-body-strong">
Is Base Lending Rate:
</div>
<div fxFlex="10%">
{{ floatingRateData.isBaseLendingRate ? 'Yes' : 'No' }}
</div>
<div fxFlex="14%" class="mat-body-strong">
Is Active:
</div>
<div fxFlex="10%">
{{ floatingRateData.isActive ? 'Yes' : 'No' }}
</div>
</div>
<br>
<mat-divider [inset]="true"></mat-divider>
<br>
<p class="mat-title">Floating Rate Periods</p>
<div class="mat-elevation-z8">
<table mat-table [dataSource]="dataSource" matSort>
<ng-container matColumnDef="fromDate">
<th mat-header-cell *matHeaderCellDef mat-sort-header> From Date </th>
<td mat-cell *matCellDef="let floatingRate"> {{ floatingRate.fromDate | date : 'dd MMMM yyyy' }} </td>
</ng-container>
<ng-container matColumnDef="interestRate">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Interest Rate </th>
<td mat-cell *matCellDef="let floatingRate"> {{ floatingRate.interestRate }} </td>
</ng-container>
<ng-container matColumnDef="isDifferential">
<th mat-header-cell *matHeaderCellDef mat-sort-header> Is Differential? </th>
<td mat-cell *matCellDef="let floatingRate">
<fa-icon *ngIf="floatingRate.isDifferentialToBaseLendingRate" icon="check-circle" size="lg"
class="is-differential" matTooltip="Yes" matTooltipPosition="right"></fa-icon>
<fa-icon *ngIf="!floatingRate.isDifferentialToBaseLendingRate" icon="times-circle" size="lg"
class="not-is-differential" matTooltip="No" matTooltipPosition="right"></fa-icon>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSizeOptions]="[10, 25, 50, 100]" showFirstLastButtons></mat-paginator>
</div>
</mat-card-content>
</mat-card>
</div>
@@ -0,0 +1,19 @@
table {
width: 100%;
}
// TODO: CONFIGURE THESE CLASSES GLOBALLY
.is-differential {
color: #32cd32;
}
.not-is-differential {
color: #f44366;
}
.content {
div {
margin: 1rem 0;
word-wrap: break-word;
}
}
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ViewFloatingRateComponent } from './view-floating-rate.component';
describe('ViewFloatingRateComponent', () => {
let component: ViewFloatingRateComponent;
let fixture: ComponentFixture<ViewFloatingRateComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ViewFloatingRateComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ViewFloatingRateComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,54 @@
/** Angular Imports */
import { Component, OnInit, ViewChild } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { MatTableDataSource, MatPaginator, MatSort } from '@angular/material';
/**
* View Floating Rate Component.
*/
@Component({
selector: 'mifosx-view-floating-rate',
templateUrl: './view-floating-rate.component.html',
styleUrls: ['./view-floating-rate.component.scss']
})
export class ViewFloatingRateComponent implements OnInit {
/** Floating Rate Data. */
floatingRateData: any;
/** Columns to be displayed in floating rate periods table. */
displayedColumns: string[] = ['fromDate', 'interestRate', 'isDifferential'];
/** Data source for floating rate periods table. */
dataSource: MatTableDataSource<any>;
/** Paginator for floating rate periods table. */
@ViewChild(MatPaginator) paginator: MatPaginator;
/** Sorter for floating rate periods table. */
@ViewChild(MatSort) sort: MatSort;
/**
* Retrieves the floating rate data from `resolve`.
* @param {ActivatedRoute} route Activated Route.
*/
constructor(private route: ActivatedRoute) {
this.route.data.subscribe(( data: { floatingRate: any } ) => {
this.floatingRateData = data.floatingRate;
});
}
/**
* Sets the floating rate periods table.
*/
ngOnInit() {
this.setFloatingRates();
}
/**
* Initializes the data source, paginator and sorter for floating rate periods table.
*/
setFloatingRates() {
this.dataSource = new MatTableDataSource(this.floatingRateData.ratePeriods);
this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort;
}
}
+48 -1
View File
@@ -29,6 +29,10 @@ import { ViewChargeComponent } from './charges/view-charge/view-charge.component
import { FixedDepositProductsComponent } from './fixed-deposit-products/fixed-deposit-products.component';
import { CreateFixedDepositProductComponent } from './fixed-deposit-products/create-fixed-deposit-product/create-fixed-deposit-product.component';
import { ProductsMixComponent } from './products-mix/products-mix.component';
import { FloatingRatesComponent } from './floating-rates/floating-rates.component';
import { CreateFloatingRateComponent } from './floating-rates/create-floating-rate/create-floating-rate.component';
import { ViewFloatingRateComponent } from './floating-rates/view-floating-rate/view-floating-rate.component';
import { EditFloatingRateComponent } from './floating-rates/edit-floating-rate/edit-floating-rate.component';
import { ManageTaxComponentsComponent } from './manage-tax-components/manage-tax-components.component';
import { ManageTaxGroupsComponent } from './manage-tax-groups/manage-tax-groups.component';
import { ViewTaxComponentComponent } from './manage-tax-components/view-tax-component/view-tax-component.component';
@@ -52,6 +56,8 @@ import { ChargeResolver } from './charges/charge.resolver';
import { FixedDepositProductsResolver } from './fixed-deposit-products/fixed-deposit-products.resolver';
import { FixedDepositProductsTemplateResolver } from './fixed-deposit-products/fixed-deposit-products-template.resolver';
import { ProductsMixResolver } from './products-mix/products-mix.resolver';
import { FloatingRatesResolver } from './floating-rates/floating-rates.resolver';
import { FloatingRateResolver } from './floating-rates/floating-rate.resolver';
import { ManageTaxComponentsResolver } from './manage-tax-components/manage-tax-components.resolver';
import { ManageTaxGroupsResolver } from './manage-tax-groups/manage-tax-groups.resolver';
import { TaxComponentResolver } from './manage-tax-components/tax-component.resolver';
@@ -295,6 +301,45 @@ const routes: Routes = [
},
data: { title: extract('Products Mix'), breadcrumb: 'Products Mix' },
},
{
path: 'floating-rates',
data: { title: extract('Floating Rates'), breadcrumb: 'Floating Rates' },
children: [
{
path: '',
component: FloatingRatesComponent,
resolve: {
floatingrates: FloatingRatesResolver
}
},
{
path: 'create',
component: CreateFloatingRateComponent,
data: { title: extract('Create Floating Rate'), breadcrumb: 'Create' }
},
{
path: ':id',
data: { title: extract('View Floating Rate'), routeParamBreadcrumb: 'id' },
children: [
{
path: '',
component: ViewFloatingRateComponent,
resolve: {
floatingRate: FloatingRateResolver
}
},
{
path: 'edit',
component: EditFloatingRateComponent,
data: { title: extract('Edit Floating Rate'), breadcrumb: 'Edit', routeParamBreadcrumb: false },
resolve: {
floatingRate: FloatingRateResolver
}
}
]
}
]
}
]
}
])
@@ -329,7 +374,9 @@ const routes: Routes = [
ProductsMixResolver,
ManageTaxComponentsResolver,
ManageTaxGroupsResolver,
TaxComponentResolver
TaxComponentResolver,
FloatingRateResolver,
FloatingRatesResolver
]
})
export class ProductsRoutingModule { }
+1 -1
View File
@@ -80,7 +80,7 @@
<p matLine>Define Tax components and Tax groups</p>
</mat-list-item>
<mat-list-item>
<mat-list-item [routerLink]="['floating-rates']">
<mat-icon matListIcon>
<fa-icon icon="money-bill-alt" size="sm"></fa-icon>
</mat-icon>
+12 -1
View File
@@ -62,6 +62,11 @@ import { FixedDepositProductPreviewStepComponent } from './fixed-deposit-product
import { DepositProductIncentiveFormDialogComponent } from './deposit-product-incentive-form-dialog/deposit-product-incentive-form-dialog.component';
import { ManageTaxGroupsComponent } from './manage-tax-groups/manage-tax-groups.component';
import { ViewTaxComponentComponent } from './manage-tax-components/view-tax-component/view-tax-component.component';
import { FloatingRatesComponent } from './floating-rates/floating-rates.component';
import { CreateFloatingRateComponent } from './floating-rates/create-floating-rate/create-floating-rate.component';
import { ViewFloatingRateComponent } from './floating-rates/view-floating-rate/view-floating-rate.component';
import { EditFloatingRateComponent } from './floating-rates/edit-floating-rate/edit-floating-rate.component';
import { FloatingRatePeriodDialogComponent } from './floating-rates/floating-rate-period-dialog/floating-rate-period-dialog.component';
/**
* Products Module
@@ -90,7 +95,13 @@ import { ViewTaxComponentComponent } from './manage-tax-components/view-tax-comp
ChargesComponent,
ViewChargeComponent,
FixedDepositProductsComponent,
ManageTaxComponentsComponent,
ProductsMixComponent,
FloatingRatesComponent,
CreateFloatingRateComponent,
ViewFloatingRateComponent,
EditFloatingRateComponent,
FloatingRatePeriodDialogComponent,
ManageTaxComponentsComponent,
ViewLoanProductComponent,
EditLoanProductComponent,
@@ -131,7 +142,7 @@ import { ViewTaxComponentComponent } from './manage-tax-components/view-tax-comp
ViewTaxComponentComponent
],
entryComponents: [
DepositProductIncentiveFormDialogComponent
FloatingRatePeriodDialogComponent
],
providers: [DatePipe]
})
+32
View File
@@ -166,4 +166,36 @@ export class ProductsService {
return this.http.get('/loanproducts', { params: httpParams });
}
/**
* @returns {Observable<any>} Floating Rates data.
*/
getFloatingRates(): Observable<any> {
return this.http.get('/floatingrates');
}
/**
* @param {any} floatingRate Floating Rate.
* @returns {Observable<any>}
*/
createFloatingRate(floatingRate: any): Observable<any> {
return this.http.post('/floatingrates', floatingRate);
}
/**
* @param {string} floatingRateId Floating Rate ID.
* @returns {Observable<any>}
*/
getFloatingRate(floatingRateId: string): Observable<any> {
return this.http.get(`/floatingrates/${floatingRateId}`);
}
/**
* @param {string} floatingRateId Floating Rate ID.
* @param {any} floatingRate Changes in Floating Rate.
* @returns {Observable<any>}
*/
updateFloatingRate(floatingRateId: string, floatingRate: any): Observable<any> {
return this.http.put(`/floatingrates/${floatingRateId}`, floatingRate);
}
}