feat: view fixed-deposit account page (#959)

Fixes: #225
This commit is contained in:
Karan Takalkar
2020-07-02 20:49:49 +05:30
committed by GitHub
parent 50dbb7b6e6
commit 87604b4e3e
32 changed files with 1333 additions and 2 deletions
@@ -173,6 +173,10 @@ const routes: Routes = [
data: { title: extract('Loans'), breadcrumb: 'loans', routeParamBreadcrumb: false },
loadChildren: '../loans/loans.module#LoansModule'
},
{
path: 'fixed-deposits-accounts',
loadChildren: '../deposits/fixed-deposits/fixed-deposits.module#FixedDepositsModule'
},
{
path: 'savingsaccounts',
loadChildren: '../savings/savings.module#SavingsModule'
@@ -374,7 +374,7 @@
<tr mat-header-row *matHeaderRowDef="openSavingsColumns"></tr>
<tr mat-row *matRowDef="let row; columns: openSavingsColumns;"
[routerLink]="['../', 'savingsaccounts', row.id, 'transactions']"></tr>
[routerLink]="['../', 'fixed-deposits-accounts', row.id, 'interest-rate-chart']"></tr>
</table>
<!-- Closed Fixed Deposit Accounts -->
@@ -399,7 +399,8 @@
</ng-container>
<tr mat-header-row *matHeaderRowDef="closedSavingsColumns"></tr>
<tr mat-row *matRowDef="let row; columns: closedSavingsColumns;"></tr>
<tr mat-row *matRowDef="let row; columns: closedSavingsColumns;"
[routerLink]="['../', 'fixed-deposits-account', row.id]"></tr>
</table>
<!-- Recurring Deposit Table -->
@@ -0,0 +1,32 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
/** rxjs Imports */
import { Observable } from 'rxjs';
/** Custom Services */
import { FixedDepositsService } from 'app/deposits/fixed-deposits/fixed-deposits.service';
/**
* Fixed Deposits Account data resolver.
*/
@Injectable()
export class FixedDepositsAccountViewResolver implements Resolve<Object> {
/**
* @param {FixedDepositsService} fixedDepositsService Fixed Deposits service.
*/
constructor(private fixedDepositsService: FixedDepositsService) { }
/**
* Returns the Fixed Deposits Account data.
* @param {ActivatedRouteSnapshot} route Route Snapshot
* @returns {Observable<any>}
*/
resolve(route: ActivatedRouteSnapshot): Observable<any> {
const fixedDepositAccountId = route.paramMap.get('fixedDepositAccountId');
return this.fixedDepositsService.getFixedDepositsAccountData(fixedDepositAccountId);
}
}
@@ -0,0 +1,101 @@
<div class="tab-container mat-typography">
<div fxLayout="row" fxLayoutAlign="start">
<div class="m-b-10">
<h3>All Charges</h3>
</div>
<div class="action-button m-b-20" *ngIf="this.chargesData">
<button mat-raised-button color="primary" (click)="toggleCharges()">
{{showInactiveCharges?'View Active Charges':'View Inactive Charges'}}</button>
</div>
</div>
<div class="mat-elevation-z1 m-b-25">
<table mat-table #chargesTable [dataSource]="dataSource" >
<ng-container matColumnDef="name">
<th mat-header-cell *matHeaderCellDef> Name </th>
<td mat-cell *matCellDef="let charge"> {{ charge.name }} </td>
</ng-container>
<ng-container matColumnDef="feeOrPenalty">
<th mat-header-cell *matHeaderCellDef> Fee/Penalty </th>
<td mat-cell *matCellDef="let charge"> {{ charge.penalty === true ? 'Penalty' : 'Fee' }} </td>
</ng-container>
<ng-container matColumnDef="paymentDueAt">
<th mat-header-cell *matHeaderCellDef> Payment Due At </th>
<td mat-cell *matCellDef="let charge"> {{ charge.chargeTimeType.value }} </td>
</ng-container>
<ng-container matColumnDef="dueAsOf">
<th mat-header-cell *matHeaderCellDef> Due As Of </th>
<td mat-cell *matCellDef="let charge"> {{ charge.dueDate | date }} </td>
</ng-container>
<ng-container matColumnDef="repeatsOn">
<th mat-header-cell *matHeaderCellDef> Repeats On (M/d) </th>
<td mat-cell *matCellDef="let charge"> {{ charge.feeOnMonthDay ? charge.feeOnMonthDay.join('/') : '' }} </td>
</ng-container>
<ng-container matColumnDef="calculationType">
<th mat-header-cell *matHeaderCellDef> Calculation Type </th>
<td mat-cell *matCellDef="let charge"> {{charge.chargeCalculationType.value}} </td>
</ng-container>
<ng-container matColumnDef="due">
<th mat-header-cell *matHeaderCellDef> Due </th>
<td mat-cell *matCellDef="let charge"> {{charge.currency.displaySymbol}}&nbsp;{{charge.amount}} </td>
</ng-container>
<ng-container matColumnDef="paid">
<th mat-header-cell *matHeaderCellDef> Paid </th>
<td mat-cell *matCellDef="let charge"> {{charge.currency.displaySymbol}}&nbsp;{{charge.amountPaid}} </td>
</ng-container>
<ng-container matColumnDef="waived">
<th mat-header-cell *matHeaderCellDef> Waived </th>
<td mat-cell *matCellDef="let charge"> {{charge.currency.displaySymbol}}&nbsp;{{charge.amountWaived}} </td>
</ng-container>
<ng-container matColumnDef="outstanding">
<th mat-header-cell *matHeaderCellDef> Outstanding </th>
<td mat-cell *matCellDef="let charge"> {{charge.currency.displaySymbol}}&nbsp;{{charge.amountOutstanding}} </td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> Actions </th>
<td mat-cell *matCellDef="let charge">
<span *ngIf="fixedDepositsAccountData.status.value === 'Submitted and pending approval'">
<button class="account-action-button" mat-raised-button color="primary" matTooltip="Edit Charge">
<i class="fa fa-pencil"></i>
</button>
<button class="account-action-button" mat-raised-button color="warn" matTooltip="Delete Charge">
<i class="fa fa-trash"></i>
</button>
</span>
<span *ngIf="fixedDepositsAccountData.status.value === 'Active' && charge.amountOutstanding !== 0">
<button class="account-action-button" mat-raised-button color="primary" matTooltip="Pay Charge">
<i class="fa fa-dollar"></i>
</button>
<button class="account-action-button" mat-raised-button color="primary" matTooltip="Waive Charge">
<i class="fa fa-flag"></i>
</button>
<ng-container *ngIf="isRecurringCharge(charge)">
<button class="account-action-button" mat-raised-button color="primary" matTooltip="Inactivate Charge">
<i class="fa fa-ban"></i>
</button>
</ng-container>
</span>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</div>
@@ -0,0 +1,19 @@
.tab-container {
padding: 1%;
margin: 1%;
h3 {
margin:1% auto;
}
.action-button {
margin-left: auto;
}
table {
width: 100%;
.account-action-button{
min-width: 26px;
padding: 0 6px;
margin: 4px;
line-height: 25px;
}
}
}
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { ChargesTabComponent } from './charges-tab.component';
describe('ChargesTabComponent', () => {
let component: ChargesTabComponent;
let fixture: ComponentFixture<ChargesTabComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ ChargesTabComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(ChargesTabComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,81 @@
/** Angular Imports */
import { Component, OnInit, ViewChild } from '@angular/core';
import { MatTableDataSource, MatTable } from '@angular/material';
import { ActivatedRoute } from '@angular/router';
/**
* Charges Tab Component
*/
@Component({
selector: 'mifosx-charges-tab',
templateUrl: './charges-tab.component.html',
styleUrls: ['./charges-tab.component.scss']
})
export class ChargesTabComponent implements OnInit {
/** Fixed Deposits Account Data */
fixedDepositsAccountData: any;
/** Charges Data */
chargesData: any[];
/** Data source for charges table. */
dataSource: MatTableDataSource<any>;
/** Toggles Charges Table */
showInactiveCharges = false;
/** Columns to be displayed in charges table. */
displayedColumns: string[] = [
'name',
'feeOrPenalty',
'paymentDueAt',
'dueAsOf',
'repeatsOn',
'calculationType',
'due',
'paid',
'waived',
'outstanding',
'actions'
];
/** Charges Table Reference */
@ViewChild('chargesTable') chargesTableRef: MatTable<Element>;
/**
* Retrieves Fixed Deposits Account Data from `resolve`.
* @param {ActivatedRoute} route Activated Route.
*/
constructor(private route: ActivatedRoute) {
this.route.parent.data.subscribe((data: { fixedDepositsAccountData: any }) => {
this.fixedDepositsAccountData = data.fixedDepositsAccountData;
this.chargesData = this.fixedDepositsAccountData.charges;
});
}
ngOnInit() {
const activeCharges = this.chargesData ? this.chargesData.filter(charge => charge.isActive) : [];
this.dataSource = new MatTableDataSource(activeCharges);
}
/**
* Toggles datasource for active/inactive charges.
*/
toggleCharges() {
this.showInactiveCharges = !this.showInactiveCharges;
if (!this.showInactiveCharges) {
const activeCharges = this.chargesData.filter(charge => charge.isActive);
this.dataSource.data = activeCharges;
} else {
const inActiveCharges = this.chargesData.filter(charge => !charge.isActive);
this.dataSource.data = inActiveCharges;
}
this.chargesTableRef.renderRows();
}
/**
* Checks if charge is recurring.
* @param {any} charge Charge
*/
isRecurringCharge(charge: any) {
return charge.chargeTimeType.value === 'Monthly Fee' || charge.chargeTimeType.value === 'Annual Fee' || charge.chargeTimeType.value === 'Weekly Fee';
}
}
@@ -0,0 +1,16 @@
@import "~@angular/material/theming";
@mixin fixed-deposits-account-view-component-theme($theme) {
$primary: map-get($theme, primary);
mifosx-fixed-deposit-account-view {
.fixed-deposits-account-card {
.header {
background-color: mat-color($primary, 500);
}
.table-headers {
background-color: mat-color($primary, 500);
color: mat-contrast($primary, 500);
}
}
}
}
@@ -0,0 +1,200 @@
<mat-card class="fixed-deposits-account-card">
<mat-card-header fxLayout="column" class="header">
<mat-card-title-group class="header-title-group">
<div class="profile-image-container">
<div>
<img mat-card-md-image class="profile-image"
matTooltip="Fixed Deposits Account"
[src]="'assets/images/fd_account_placeholder.png'">
</div>
</div>
<div class="mat-typography account-card-title">
<mat-card-title>
<h3>
<i class="fa fa-stop" [ngClass]="fixedDepositsAccountData.status.code | statusLookup" [matTooltip]="fixedDepositsAccountData.status.value"></i>
Account Name : {{fixedDepositsAccountData.depositProductName}}
</h3>
</mat-card-title>
<mat-card-subtitle>
<p>
Account #: {{fixedDepositsAccountData.accountNo}} | Client Name: {{fixedDepositsAccountData.clientName}}<br/>
<span *ngIf="!fixedDepositsAccountData.status.rejected && !fixedDepositsAccountData.status.submittedAndPendingApproval">
Current Balance: {{fixedDepositsAccountData.currency.displaySymbol}}&nbsp;{{fixedDepositsAccountData.summary.accountBalance}}<br/>
Deposit Amount: {{fixedDepositsAccountData.currency.displaySymbol}}&nbsp;{{fixedDepositsAccountData.depositAmount}}<br/>
</span>
</p>
</mat-card-subtitle>
</div>
</mat-card-title-group>
<mat-card-actions class="account-actions">
<ng-container *ngFor="let button of buttonConfig.singleButtons">
<button mat-raised-button>
<i class="{{button.icon}}"></i> {{button.name}}</button>
</ng-container>
<ng-container *ngIf="buttonConfig.options">
<button mat-raised-button [matMenuTriggerFor]="More">More</button>
<mat-menu #More="matMenu">
<span *ngFor="let option of buttonConfig.options">
<button mat-menu-item >{{option.name}}</button>
</span>
</mat-menu>
</ng-container>
</mat-card-actions>
</mat-card-header>
<mat-card-content class="content">
<div class="fixed-deposits-account-tables" fxLayout="row" fxLayoutGap="2%">
<div fxFlex="49%" fxLayout="column" fxLayoutGap="4%">
<div>
<h4 class="table-headers">Fixed Deposits Details</h4>
<table>
<tbody>
<tr>
<td>Activated On</td>
<td>{{fixedDepositsAccountData.timeline.activatedOnDate ? (fixedDepositsAccountData.timeline.activatedOnDate | date) : 'Not Activated'}}</td>
</tr>
<tr *ngIf="fixedDepositsAccountData.timeline.closedOnDate">
<td>Closed On</td>
<td>{{fixedDepositsAccountData.timeline.closedOnDate | date}}</td>
</tr>
<tr>
<td>Field Officer</td>
<td>{{fixedDepositsAccountData.fieldOfficerName ? fixedDepositsAccountData.fieldOfficerName : 'Unassigned'}}</td>
</tr>
<tr>
<td>Maturity Date</td>
<td>{{fixedDepositsAccountData.maturityDate ? (fixedDepositsAccountData.maturityDate | date) : 'N/A'}}</td>
</tr>
<tr>
<td>Deposit Period</td>
<td>{{fixedDepositsAccountData.depositPeriod}}&nbsp;{{fixedDepositsAccountData.depositPeriodFrequency.value}}</td>
</tr>
<tr *ngIf="fixedDepositsAccountData.withHoldTax">
<td>Tax Group</td>
<td>{{fixedDepositsAccountData.taxGroup.name}}</td>
</tr>
</tbody>
</table>
</div>
<div>
<h4 class="table-headers">Interest Details</h4>
<table>
<tbody>
<tr>
<td>Interest Rate</td>
<td>{{fixedDepositsAccountData.nominalAnnualInterestRate}}%</td>
</tr>
<tr>
<td>Interest Compounding Period</td>
<td>{{fixedDepositsAccountData.interestCompoundingPeriodType.value}}</td>
</tr>
<tr>
<td>Interest Posting Period</td>
<td>{{fixedDepositsAccountData.interestPostingPeriodType.value}}</td>
</tr>
<tr>
<td>Interest Calculated Using</td>
<td>{{fixedDepositsAccountData.interestCalculationType.value}}</td>
</tr>
<tr>
<td>No. of Days in Year</td>
<td>{{fixedDepositsAccountData.interestCalculationDaysInYearType.value}}</td>
</tr>
<tr *ngIf="fixedDepositsAccountData.preClosurePenalApplicable">
<td>Pre-cloure Penal</td>
<td>{{fixedDepositsAccountData.preClosurePenalInterest}} % on {{fixedDepositsAccountData.preClosurePenalInterestOnType.value}}</td>
</tr>
</table>
</div>
</div>
<div fxFlex="49%">
<div *ngIf="!fixedDepositsAccountData.status.rejected && !fixedDepositsAccountData.status.submittedAndPendingApproval; else otherDetails">
<h4 class="table-headers">Performance History</h4>
<table>
<tbody>
<tr>
<td>Principal Amount</td>
<td>{{fixedDepositsAccountData.currency.displaySymbol}}&nbsp;{{fixedDepositsAccountData.depositAmount}}</td>
</tr>
<tr>
<td>Maturity Amount</td>
<td>{{fixedDepositsAccountData.currency.displaySymbol}}&nbsp;{{fixedDepositsAccountData.maturityAmount}}</td>
</tr>
<tr *ngIf="fixedDepositsAccountData.summary.totalDeposits">
<td>Total Deposits</td>
<td>{{fixedDepositsAccountData.currency.displaySymbol}}&nbsp;{{fixedDepositsAccountData.summary.totalDeposits}}</td>
</tr>
<tr *ngIf="fixedDepositsAccountData.summary.totalWithdrawals">
<td>Total Withdrawals</td>
<td>{{fixedDepositsAccountData.currency.displaySymbol}}&nbsp;{{fixedDepositsAccountData.summary.totalWithdrawals}}</td>
</tr>
<tr *ngIf="fixedDepositsAccountData.summary.totalInterestEarned >= 0">
<td>Total Interest Earned</td>
<td>{{fixedDepositsAccountData.currency.displaySymbol}}&nbsp;{{fixedDepositsAccountData.summary.totalInterestEarned}}</td>
</tr>
</table>
</div>
<ng-template #otherDetails>
<div>
<h4 class="table-headers">Other Details</h4>
<table>
<tbody>
<tr>
<td>Principal Amount</td>
<td>{{fixedDepositsAccountData.currency.displaySymbol}}&nbsp;{{fixedDepositsAccountData.depositAmount}}</td>
</tr>
<tr>
<td>Maturity Amount</td>
<td>{{fixedDepositsAccountData.currency.displaySymbol}}&nbsp;{{fixedDepositsAccountData.maturityAmount}}</td>
</tr>
</tbody>
</table>
</div>
</ng-template>
</div>
</div>
<nav mat-tab-nav-bar class="navigation-tabs">
<a mat-tab-link [routerLink]="['./interest-rate-chart']" routerLinkActive #IRC="routerLinkActive"
[active]="IRC.isActive">
Ineterest Rate Chart
</a>
<a mat-tab-link [routerLink]="['./transactions']" routerLinkActive #transactions="routerLinkActive"
[active]="transactions.isActive">
Transactions
</a>
<a mat-tab-link [routerLink]="['./charges']" routerLinkActive #charges="routerLinkActive"
[active]="charges.isActive">
Charges
</a>
<a mat-tab-link [routerLink]="['./standing-instructions']" routerLinkActive #standingInstructions="routerLinkActive"
[active]="standingInstructions.isActive" *ngIf="fixedDepositsAccountData.clientId">
Standing Instructions
</a>
</nav>
<router-outlet></router-outlet>
</mat-card-content>
</mat-card>
@@ -0,0 +1,53 @@
.fixed-deposits-account-card {
margin: 0 auto;
max-width: 80rem;
width: 90%;
padding: 0;
.header {
padding: 1%;
.header-title-group {
.account-card-title {
color: white;
width: 90%;
p {
color: white;
}
}
}
.profile-image-container {
margin: 1%;
.profile-image {
object-fit: cover;
border-radius: 20px;
}
}
.account-actions {
align-self: flex-end;
margin: 0 1%;
i {
margin-bottom: 2px;
margin-right: 4px;
}
}
}
.navigation-tabs {
background-color: #f2f2f2;
overflow: auto;
}
.content {
.fixed-deposits-account-tables {
padding: 1%;
margin: 1%;
.table-headers {
margin: 0;
padding: 6px;
}
td {
padding: 3px;
}
}
}
i, img:hover {
cursor: pointer;
}
}
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { FixedDepositAccountViewComponent } from './fixed-deposit-account-view.component';
describe('FixedDepositAccountViewComponent', () => {
let component: FixedDepositAccountViewComponent;
let fixture: ComponentFixture<FixedDepositAccountViewComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ FixedDepositAccountViewComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(FixedDepositAccountViewComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,54 @@
/** Angular Imports */
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { FixedDepositsButtonsConfiguration } from './fixed-deposits-buttons.config';
/**
* Fixed Deposits Account View Component
*/
@Component({
selector: 'mifosx-fixed-deposit-account-view',
templateUrl: './fixed-deposit-account-view.component.html',
styleUrls: ['./fixed-deposit-account-view.component.scss']
})
export class FixedDepositAccountViewComponent implements OnInit {
/** Fixed Deposits Account Data */
fixedDepositsAccountData: any;
/** Button Configurations */
buttonConfig: FixedDepositsButtonsConfiguration;
/**
* Fetches fixed deposits account data from `resolve`
* @param {ActivatedRoute} route Activated Route
*/
constructor(private route: ActivatedRoute) {
this.route.data.subscribe((data: { fixedDepositsAccountData: any }) => {
this.fixedDepositsAccountData = data.fixedDepositsAccountData;
});
}
ngOnInit() {
this.setConditionalButtons();
}
/**
* Adds options to button config. conditionaly.
*/
setConditionalButtons() {
const status = this.fixedDepositsAccountData.status.value;
this.buttonConfig = new FixedDepositsButtonsConfiguration(status);
if (this.fixedDepositsAccountData.taxGroup && status === 'Active') {
if (this.fixedDepositsAccountData.withHoldTax) {
this.buttonConfig.addOption({
name: 'Disable Withhold Tax'
});
} else {
this.buttonConfig.addOption({
name: 'Enable Withhold Tax'
});
}
}
}
}
@@ -0,0 +1,120 @@
/** Fixed Deposits Account Buttons Configuration */
export class FixedDepositsButtonsConfiguration {
optionArray: {
name: string
}[];
buttonsArray: {
name: string,
icon: string,
}[];
constructor(status: string) {
this.setOptions(status);
this.setButtons(status);
}
get singleButtons() {
return this.buttonsArray;
}
get options() {
return this.optionArray;
}
setButtons(status: string) {
switch (status) {
case 'Active':
this.buttonsArray = [
{
name: 'Premature Close',
icon: 'fa fa-arrow-left'
},
{
name: 'Calculate Interest',
icon: 'fa fa-table'
}
];
break;
case 'Matured':
this.buttonsArray = [
{
name: 'Close',
icon: 'fa fa-arrow-right'
},
{
name: 'Calculate Interest',
icon: 'fa fa-table'
}
];
break;
case 'Submitted and pending approval':
this.buttonsArray = [
{
name: 'Modify Application',
icon: 'fa fa-pencil '
},
{
name: 'Approve',
icon: 'fa fa-check'
}
];
break;
case 'Approved':
this.buttonsArray = [
{
name: 'Undo Approval',
icon: 'fa fa-undo'
},
{
name: 'Activate',
icon: 'fa fa-check'
}
];
break;
default:
this.buttonsArray = [];
}
}
setOptions(status: string) {
switch (status) {
case 'Active':
case 'Matured':
this.optionArray = [
{
name: 'Post Interest'
},
{
name: 'Add Charge'
}
];
break;
case 'Submitted and pending approval':
this.optionArray = [
{
name: 'Reject'
},
{
name: 'Withdraw By Client'
},
{
name: 'Add Charge'
},
{
name: 'Delete'
}
];
break;
case 'Approved':
default:
this.optionArray = [];
}
}
addOption(option: {name: string}) {
this.optionArray.push(option);
}
}
@@ -0,0 +1,44 @@
<div class="tab-container mat-typography">
<div class="mat-elevation-z1 m-b-25">
<table mat-table [dataSource]="dataSource" >
<ng-container matColumnDef="period">
<th mat-header-cell *matHeaderCellDef> Period </th>
<td mat-cell *matCellDef="let rateChart">{{rateChart.fromPeriod}}-{{rateChart.toPeriod}}&nbsp;{{rateChart.periodType.value}}</td>
</ng-container>
<ng-container matColumnDef="amountRange">
<th mat-header-cell *matHeaderCellDef> Amount Range </th>
<td mat-cell *matCellDef="let rateChart">{{rateChart.amountRangeFrom}}-{{rateChart.amountRangeTo}}</td>
</ng-container>
<ng-container matColumnDef="interest">
<th mat-header-cell *matHeaderCellDef> Interest </th>
<td mat-cell *matCellDef="let rateChart"> {{ rateChart.annualInterestRate }} </td>
</ng-container>
<ng-container matColumnDef="description">
<th mat-header-cell *matHeaderCellDef> Description </th>
<td mat-cell *matCellDef="let rateChart"> {{ rateChart.description }} </td>
</ng-container>
<ng-container matColumnDef="incentives">
<th mat-header-cell *matHeaderCellDef> Incentives </th>
<td mat-cell *matCellDef="let rateChart">
<button mat-button color="primary">
<fa-icon icon="eye"></fa-icon>&nbsp;&nbsp;
View Incentives
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</div>
@@ -0,0 +1,10 @@
.tab-container {
padding: 1%;
margin: 1%;
h3 {
margin:1% auto;
}
table {
width: 100%;
}
}
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { InterestRateChartTabComponent } from './interest-rate-chart-tab.component';
describe('InterestRateChartTabComponent', () => {
let component: InterestRateChartTabComponent;
let fixture: ComponentFixture<InterestRateChartTabComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ InterestRateChartTabComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(InterestRateChartTabComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,39 @@
/** Angular Imports */
import { Component, OnInit } from '@angular/core';
import { MatTableDataSource } from '@angular/material';
import { ActivatedRoute } from '@angular/router';
/**
* Interest Rate Chart Tab Component.
*/
@Component({
selector: 'mifosx-interest-rate-chart-tab',
templateUrl: './interest-rate-chart-tab.component.html',
styleUrls: ['./interest-rate-chart-tab.component.scss']
})
export class InterestRateChartTabComponent implements OnInit {
/** Fixed Deposits Account Status */
status: any;
/** Interest Rate Chart Data */
interestRateChartData: any;
/** Columns to be displayed in interest rate chart table. */
displayedColumns: string[] = ['period', 'amountRange', 'interest', 'description', 'incentives'];
/** Data source for interest rate chart table. */
dataSource: MatTableDataSource<any>;
/**
* Retrieves fixed deposits account data from `resolve`.
* @param {ActivatedRoute} route Activated Route.
*/
constructor(private route: ActivatedRoute) {
this.route.parent.data.subscribe((data: { fixedDepositsAccountData: any }) => {
this.interestRateChartData = data.fixedDepositsAccountData.accountChart.chartSlabs;
});
}
ngOnInit() {
this.dataSource = new MatTableDataSource(this.interestRateChartData);
}
}
@@ -0,0 +1,70 @@
<div class="tab-container mat-typography">
<div class="m-b-10">
<h3>All Standing Instructions</h3>
</div>
<div class="mat-elevation-z1 m-b-25">
<table mat-table #instructionsTable [dataSource]="dataSource">
<ng-container matColumnDef="client">
<th mat-header-cell *matHeaderCellDef> Client </th>
<td mat-cell *matCellDef="let instruction">{{instruction.fromClient.displayName}}-{{instruction.fromClient.id}}</td>
</ng-container>
<ng-container matColumnDef="fromAccount">
<th mat-header-cell *matHeaderCellDef> From Account </th>
<td mat-cell *matCellDef="let instruction">{{instruction.fromAccount.accountNo}} ({{instruction.fromAccountType.value}})</td>
</ng-container>
<ng-container matColumnDef="beneficiary">
<th mat-header-cell *matHeaderCellDef> Beneficiary </th>
<td mat-cell *matCellDef="let instruction">{{instruction.toClient.displayName}}</td>
</ng-container>
<ng-container matColumnDef="toAccount">
<th mat-header-cell *matHeaderCellDef> To Account </th>
<td mat-cell *matCellDef="let instruction">{{instruction.toAccount.accountNo}} ({{instruction.toAccountType.value}})</td>
</ng-container>
<ng-container matColumnDef="amount">
<th mat-header-cell *matHeaderCellDef> Amount </th>
<td mat-cell *matCellDef="let instruction">{{instruction.instructionType.value}}/{{instruction.amount}}</td>
</ng-container>
<ng-container matColumnDef="validity">
<th mat-header-cell *matHeaderCellDef> Validity </th>
<td mat-cell *matCellDef="let instruction">{{instruction.validFrom | date}} to {{instruction.validTill | date}}</td>
</ng-container>
<ng-container matColumnDef="actions">
<th mat-header-cell *matHeaderCellDef> Actions </th>
<td mat-cell *matCellDef="let instruction">
<span *ngIf="instruction.status.value!=='Deleted'">
<button class="account-action-button" mat-raised-button color="primary" matTooltip="Edit Standing Instruction"
*mifosxHasPermission="'UPDATE_STANDINGINSTRUCTION'">
<i class="fa fa-edit"></i>
</button>
</span>
<span *ngIf="instruction.status.value!=='Deleted'">
<button class="account-action-button" mat-raised-button color="warn" matTooltip="Delete Standing Instruction"
*mifosxHasPermission="'DELETE_STANDINGINSTRUCTION'">
<i class="fa fa-times"></i>
</button>
</span>
<button class="account-action-button" mat-raised-button color="primary" matTooltip="View Standing Instruction"
*mifosxHasPermission="'READ_STANDINGINSTRUCTION'">
<i class="fa fa-eye"></i>
</button>
</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</div>
@@ -0,0 +1,19 @@
.tab-container {
padding: 1%;
margin: 1%;
h3 {
margin:1% auto;
}
.action-button {
margin-left: auto;
}
table {
width: 100%;
.account-action-button{
min-width: 26px;
padding: 0 6px;
margin: 4px;
line-height: 25px;
}
}
}
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { StandingInstructionsTabComponent } from './standing-instructions-tab.component';
describe('StandingInstructionsTabComponent', () => {
let component: StandingInstructionsTabComponent;
let fixture: ComponentFixture<StandingInstructionsTabComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ StandingInstructionsTabComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(StandingInstructionsTabComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,70 @@
/** Angular Imports */
import { Component, OnInit, ViewChild } from '@angular/core';
import { MatTableDataSource, MatTable } from '@angular/material';
import { ActivatedRoute } from '@angular/router';
/** Custom Services */
import { FixedDepositsService } from 'app/deposits/fixed-deposits/fixed-deposits.service';
/**
* Fixed Deposits Standing Instructions Tab
*/
@Component({
selector: 'mifosx-standing-instructions-tab',
templateUrl: './standing-instructions-tab.component.html',
styleUrls: ['./standing-instructions-tab.component.scss']
})
export class StandingInstructionsTabComponent implements OnInit {
/** Fixed Deposits Data */
fixedDepositsData: any;
/** Instructions Data */
instructionsData: any[];
/** Data source for instructions table. */
dataSource = new MatTableDataSource();
/** Columns to be displayed in instructions table. */
displayedColumns: string[] = [
'client',
'fromAccount',
'beneficiary',
'toAccount',
'amount',
'validity',
'actions'
];
/** Instruction Table Reference */
@ViewChild('instructionsTable') instructionTableRef: MatTable<Element>;
/**
* Retrieves Fixed Deposits Account Data from `resolve`.
* @param {ActivatedRoute} route Activated Route.
*/
constructor(private route: ActivatedRoute,
private fixedDepositsService: FixedDepositsService) {
this.route.parent.data.subscribe((data: { fixedDepositsAccountData: any }) => {
this.fixedDepositsData = data.fixedDepositsAccountData;
});
}
ngOnInit() {
this.getStandingInstructions();
}
/**
* Retrieves standing instructions and initializes instructions table.
*/
getStandingInstructions() {
const clientId = this.fixedDepositsData.clientId;
const clientName = this.fixedDepositsData.clientName;
const accountId = this.fixedDepositsData.id;
const locale = 'en';
const dateFormat = 'dd MMMM yyyy';
this.fixedDepositsService.getStandingInstructions(clientId, clientName, accountId, locale, dateFormat).subscribe((response: any) => {
this.instructionsData = response.pageItems;
this.dataSource.data = this.instructionsData;
this.instructionTableRef.renderRows();
});
}
}
@@ -0,0 +1,44 @@
<div class="tab-container mat-typography">
<div class="mat-elevation-z1 m-b-25">
<table mat-table [dataSource]="dataSource" >
<ng-container matColumnDef="id">
<th mat-header-cell *matHeaderCellDef> ID </th>
<td mat-cell *matCellDef="let transaction"> {{ transaction.id }} </td>
</ng-container>
<ng-container matColumnDef="transactionDate">
<th mat-header-cell *matHeaderCellDef> Transaction Date </th>
<td mat-cell *matCellDef="let transaction"> {{ transaction.date | date }} </td>
</ng-container>
<ng-container matColumnDef="transactionType">
<th mat-header-cell *matHeaderCellDef> Transaction Type </th>
<td mat-cell *matCellDef="let transaction"> {{ transaction.transactionType.value }} </td>
</ng-container>
<ng-container matColumnDef="debit">
<th mat-header-cell *matHeaderCellDef> Debit </th>
<td mat-cell *matCellDef="let transaction"> {{ isDebit(transaction.transactionType) ? transaction.amount : 'N/A'}} </td>
</ng-container>
<ng-container matColumnDef="credit">
<th mat-header-cell *matHeaderCellDef> Credit </th>
<td mat-cell *matCellDef="let transaction"> {{ !isDebit(transaction.transactionType) ? transaction.amount : 'N/A' }} </td>
</ng-container>
<ng-container matColumnDef="balance">
<th mat-header-cell *matHeaderCellDef> Balance </th>
<td mat-cell *matCellDef="let transaction"> {{ transaction.runningBalance }} </td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
</div>
</div>
@@ -0,0 +1,10 @@
.tab-container {
padding: 1%;
margin: 1%;
h3 {
margin:1% auto;
}
table {
width: 100%;
}
}
@@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { TransactionsTabComponent } from './transactions-tab.component';
describe('TransactionsTabComponent', () => {
let component: TransactionsTabComponent;
let fixture: ComponentFixture<TransactionsTabComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ TransactionsTabComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(TransactionsTabComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
@@ -0,0 +1,49 @@
/** Angular Imports */
import { Component, OnInit } from '@angular/core';
import { MatTableDataSource } from '@angular/material';
import { ActivatedRoute } from '@angular/router';
/**
* Transactions Tab Component.
*/
@Component({
selector: 'mifosx-transactions-tab',
templateUrl: './transactions-tab.component.html',
styleUrls: ['./transactions-tab.component.scss']
})
export class TransactionsTabComponent implements OnInit {
/** Fixed Deposits Account Status */
status: any;
/** Transactions Data */
transactionsData: any;
/** Columns to be displayed in transactions table. */
displayedColumns: string[] = ['id', 'transactionDate', 'transactionType', 'debit', 'credit', 'balance'];
/** Data source for transactions table. */
dataSource: MatTableDataSource<any>;
/**
* Retrieves fixed deposits account data from `resolve`.
* @param {ActivatedRoute} route Activated Route.
*/
constructor(private route: ActivatedRoute) {
this.route.parent.data.subscribe((data: { fixedDepositsAccountData: any }) => {
this.transactionsData = data.fixedDepositsAccountData.transactions;
this.status = data.fixedDepositsAccountData.status.value;
});
}
ngOnInit() {
this.dataSource = new MatTableDataSource(this.transactionsData);
}
/**
* Checks if transaction is debit.
* @param {any} transactionType Transaction Type
*/
isDebit(transactionType: any) {
return transactionType.withdrawal === true || transactionType.feeDeduction === true
|| transactionType.overdraftInterest === true || transactionType.withholdTax === true;
}
}
@@ -0,0 +1,72 @@
/** Angular Imports */
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
/** Translation Imports */
import { extract } from 'app/core/i18n/i18n.service';
/** Custom Components */
import { FixedDepositAccountViewComponent } from './fixed-deposit-account-view/fixed-deposit-account-view.component';
import { InterestRateChartTabComponent } from './fixed-deposit-account-view/interest-rate-chart-tab/interest-rate-chart-tab.component';
import { TransactionsTabComponent } from './fixed-deposit-account-view/transactions-tab/transactions-tab.component';
import { ChargesTabComponent } from './fixed-deposit-account-view/charges-tab/charges-tab.component';
import { StandingInstructionsTabComponent } from './fixed-deposit-account-view/standing-instructions-tab/standing-instructions-tab.component';
/** Custom Resolvers */
import { FixedDepositsAccountViewResolver } from '../fixed-deposits/common-resolvers/fixed-deposit-account-view.resolver';
const routes: Routes = [
{
path: '',
data: { title: extract('All Fixed Deposits'), breadcrumb: 'Fixed Deposits', routeParamBreadcrumb: false },
children: [
{
path: ':fixedDepositAccountId',
data: { title: extract('Fixed Deposit Account View'), routeParamBreadcrumb: 'fixedDepositAccountId' },
resolve: {
},
children: [
{
path: '',
component: FixedDepositAccountViewComponent,
resolve: {
fixedDepositsAccountData: FixedDepositsAccountViewResolver
},
children: [
{
path: 'interest-rate-chart',
component: InterestRateChartTabComponent,
data: { title: extract('Fixed Deposit Account Interest Rate Chart'), breadcrumb: 'Interest Rate Chart', routeParamBreadcrumb: false },
},
{
path: 'transactions',
component: TransactionsTabComponent,
data: { title: extract('Fixed Deposit Account Transactions'), breadcrumb: 'Transactions', routeParamBreadcrumb: false },
},
{
path: 'charges',
component: ChargesTabComponent,
data: { title: extract('Fixed Deposit Account Charges'), breadcrumb: 'Charges', routeParamBreadcrumb: false }
},
{
path: 'standing-instructions',
component: StandingInstructionsTabComponent,
data: { title: extract('Fixed Deposit Account Standing Instructions'), breadcrumb: 'Standing Instructions', routeParamBreadcrumb: false }
}
]
}
]
}
]
}
];
@NgModule({
imports: [RouterModule.forChild(routes)],
exports: [RouterModule],
providers: [
FixedDepositsAccountViewResolver
]
})
export class FixedDepositsRoutingModule { }
@@ -0,0 +1,34 @@
/** Angular Imports */
import { NgModule } from '@angular/core';
import { DatePipe } from '@angular/common';
/** Custom Modules */
import { SharedModule } from 'app/shared/shared.module';
import { PipesModule } from 'app/pipes/pipes.module';
import { DirectivesModule } from 'app/directives/directives.module';
import { FixedDepositsRoutingModule } from './fixed-deposits-routing.module';
/** Custom Components */
import { FixedDepositAccountViewComponent } from './fixed-deposit-account-view/fixed-deposit-account-view.component';
import { TransactionsTabComponent } from './fixed-deposit-account-view/transactions-tab/transactions-tab.component';
import { ChargesTabComponent } from './fixed-deposit-account-view/charges-tab/charges-tab.component';
import { StandingInstructionsTabComponent } from './fixed-deposit-account-view/standing-instructions-tab/standing-instructions-tab.component';
import { InterestRateChartTabComponent } from './fixed-deposit-account-view/interest-rate-chart-tab/interest-rate-chart-tab.component';
@NgModule({
declarations: [
FixedDepositAccountViewComponent,
TransactionsTabComponent,
ChargesTabComponent,
StandingInstructionsTabComponent,
InterestRateChartTabComponent
],
imports: [
SharedModule,
PipesModule,
DirectivesModule,
FixedDepositsRoutingModule
],
providers: [DatePipe]
})
export class FixedDepositsModule { }
@@ -0,0 +1,12 @@
import { TestBed } from '@angular/core/testing';
import { FixedDepositsService } from './fixed-deposits.service';
describe('FixedDepositsService', () => {
beforeEach(() => TestBed.configureTestingModule({}));
it('should be created', () => {
const service: FixedDepositsService = TestBed.get(FixedDepositsService);
expect(service).toBeTruthy();
});
});
@@ -0,0 +1,48 @@
/** Angular Imports */
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams } from '@angular/common/http';
/** rxjs Imports */
import { Observable } from 'rxjs';
/**
* Fixed Deposits Service.
*/
@Injectable({
providedIn: 'root'
})
export class FixedDepositsService {
constructor(private http: HttpClient) {}
/**
* @param accountId Account Id of group to get data for.
* @returns {Observable<any>} Fixed Deposits data.
*/
getFixedDepositsAccountData(accountId: string): Observable<any> {
const httpParams = new HttpParams().set('associations', 'all');
return this.http.get(`/fixeddepositaccounts/${accountId}`, { params: httpParams });
}
/**
* @param clientId Client Id
* @param clientName Client Name
* @param fromAccountId Account Id
* @param locale Locale
* @param dateFormat Date Format
* @returns {Observable<any>} Standing Instructions
*/
getStandingInstructions(
clientId: string, clientName: string, fromAccountId: string,
locale: string, dateFormat: string): Observable<any> {
const httpParams = new HttpParams()
.set('clientId', clientId)
.set('clientName', clientName)
.set('fromAccountId', fromAccountId)
.set('fromAccountType', '2')
.set('locale', locale)
.set('dateFormat', dateFormat);
return this.http.get(`/standinginstructions`, { params: httpParams });
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

+2
View File
@@ -7,6 +7,7 @@
@import '../../app/loans/loans-view/loans-view.component-theme.scss';
@import '../../app/savings/savings-account-view/savings-account-view.component-theme.scss';
@import '../../app/shares/shares-account-view/shares-account-view.component-theme.scss';
@import '../../app/deposits/fixed-deposits/fixed-deposit-account-view/fixed-deposit-account-view.component-theme.scss';
// Custom material palette
$mat-denim: (
@@ -59,3 +60,4 @@ $mifosx-app-theme: mat-light-theme($mifosx-app-primary, $mifosx-app-accent, $mif
@include loans-view-component-theme($mifosx-app-theme);
@include savings-account-view-component-theme($mifosx-app-theme);
@include shares-account-view-component-theme($mifosx-app-theme);
@include fixed-deposits-account-view-component-theme($mifosx-app-theme);
@@ -7,6 +7,7 @@
@import '../../app/loans/loans-view/loans-view.component-theme.scss';
@import '../../app/savings/savings-account-view/savings-account-view.component-theme.scss';
@import '../../app/shares/shares-account-view/shares-account-view.component-theme.scss';
@import '../../app/deposits/fixed-deposits/fixed-deposit-account-view/fixed-deposit-account-view.component-theme.scss';
// Custom material palette
$mat-picton-blue: (
@@ -59,3 +60,4 @@ $mifosx-app-theme: mat-light-theme($mifosx-app-primary, $mifosx-app-accent, $mif
@include loans-view-component-theme($mifosx-app-theme);
@include savings-account-view-component-theme($mifosx-app-theme);
@include shares-account-view-component-theme($mifosx-app-theme);
@include fixed-deposits-account-view-component-theme($mifosx-app-theme);