@@ -177,6 +177,10 @@ const routes: Routes = [
|
||||
path: 'savingsaccounts',
|
||||
loadChildren: '../savings/savings.module#SavingsModule'
|
||||
},
|
||||
{
|
||||
path: 'sharesaccounts',
|
||||
loadChildren: '../shares/shares.module#SharesModule'
|
||||
},
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -318,7 +318,7 @@
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="openSharesColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: openSharesColumns;"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: openSharesColumns;" [routerLink]="['../', 'sharesaccounts', row.id, 'transactions']"></tr>
|
||||
</table>
|
||||
<!-- Closed Share Accounts -->
|
||||
<table *ngIf="showClosedShareAccounts" mat-table [dataSource]="shareAccounts|accountsFilter:'share':'closed'">
|
||||
|
||||
@@ -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 { SharesService } from '../shares.service';
|
||||
|
||||
/**
|
||||
* Shares Account data resolver.
|
||||
*/
|
||||
@Injectable()
|
||||
export class SharesAccountViewResolver implements Resolve<Object> {
|
||||
|
||||
/**
|
||||
* @param {SharesService} SharesService Shares service.
|
||||
*/
|
||||
constructor(private sharesService: SharesService) { }
|
||||
|
||||
/**
|
||||
* Returns the Shares Account data.
|
||||
* @param {ActivatedRouteSnapshot} route Route Snapshot
|
||||
* @returns {Observable<any>}
|
||||
*/
|
||||
resolve(route: ActivatedRouteSnapshot): Observable<any> {
|
||||
const shareAccountId = route.paramMap.get('shareAccountId');
|
||||
return this.sharesService.getSharesAccountData(shareAccountId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
<div class="tab-container mat-typography">
|
||||
|
||||
<div class="m-b-10">
|
||||
<h3>All Charges</h3>
|
||||
</div>
|
||||
|
||||
<div class="mat-elevation-z1 m-b-25">
|
||||
|
||||
<table mat-table [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="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}} {{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}} {{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}} {{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}} {{charge.amountOutstanding}} </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 { 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,50 @@
|
||||
/** Angular Imports */
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { MatTableDataSource } 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 {
|
||||
|
||||
/** Shares Account Data */
|
||||
sharesAccountData: any;
|
||||
/** Charges Data */
|
||||
chargesData: any[];
|
||||
/** Data source for charges table. */
|
||||
dataSource: MatTableDataSource<any>;
|
||||
/** Columns to be displayed in charges table. */
|
||||
displayedColumns: string[] = [
|
||||
'name',
|
||||
'feeOrPenalty',
|
||||
'paymentDueAt',
|
||||
'calculationType',
|
||||
'due',
|
||||
'paid',
|
||||
'waived',
|
||||
'outstanding',
|
||||
];
|
||||
|
||||
/**
|
||||
* Retrieves shares account aata from `resolve`.
|
||||
* @param {ActivatedRoute} route Activated Route.
|
||||
*/
|
||||
constructor(private route: ActivatedRoute) {
|
||||
this.route.parent.data.subscribe((data: { sharesAccountData: any }) => {
|
||||
this.sharesAccountData = data.sharesAccountData;
|
||||
this.chargesData = this.sharesAccountData.charges;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
const activeCharges = this.chargesData ? this.chargesData.filter(charge => charge.isActive) : [];
|
||||
this.dataSource = new MatTableDataSource(activeCharges);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<div class="tab-container mat-typography">
|
||||
|
||||
<div class="m-b-10">
|
||||
<h3>All Dividends</h3>
|
||||
</div>
|
||||
|
||||
<div class="mat-elevation-z1 m-b-25">
|
||||
|
||||
<table mat-table [dataSource]="dataSource" >
|
||||
|
||||
<ng-container matColumnDef="transactionDate">
|
||||
<th mat-header-cell *matHeaderCellDef> Transaction Date </th>
|
||||
<td mat-cell *matCellDef="let dividend"> {{dividend.postedDate | date}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="amount">
|
||||
<th mat-header-cell *matHeaderCellDef> Amount </th>
|
||||
<td mat-cell *matCellDef="let dividend"> {{shareAccountData.currency.displaySymbol}} {{dividend.amount}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="transactionReference">
|
||||
<th mat-header-cell *matHeaderCellDef> Transaction Reference </th>
|
||||
<td mat-cell *matCellDef="let dividend"> {{dividend.savingsTransactionId}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="status">
|
||||
<th mat-header-cell *matHeaderCellDef> status </th>
|
||||
<td mat-cell *matCellDef="let dividend"> {{dividend.status.value}} </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 { DividendsTabComponent } from './dividends-tab.component';
|
||||
|
||||
describe('DividendsTabComponent', () => {
|
||||
let component: DividendsTabComponent;
|
||||
let fixture: ComponentFixture<DividendsTabComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ DividendsTabComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(DividendsTabComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,45 @@
|
||||
/** Angular Imports */
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { MatTableDataSource } from '@angular/material';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
/**
|
||||
* Dividends Tab Component.
|
||||
*/
|
||||
@Component({
|
||||
selector: 'mifosx-dividends-tab',
|
||||
templateUrl: './dividends-tab.component.html',
|
||||
styleUrls: ['./dividends-tab.component.scss']
|
||||
})
|
||||
export class DividendsTabComponent implements OnInit {
|
||||
|
||||
/** Shares Account Data */
|
||||
shareAccountData: any;
|
||||
/** Dividends Data */
|
||||
dividendsData: any;
|
||||
/** Data source for dividends table. */
|
||||
dataSource: MatTableDataSource<any>;
|
||||
/** Columns to be displayed in dividends table. */
|
||||
displayedColumns: string[] = [
|
||||
'transactionDate',
|
||||
'amount',
|
||||
'transactionReference',
|
||||
'status'
|
||||
];
|
||||
|
||||
/**
|
||||
* Retrieves shares account data from `resolve`.
|
||||
* @param {ActivatedRoute} route Activated Route.
|
||||
*/
|
||||
constructor(private route: ActivatedRoute) {
|
||||
this.route.parent.data.subscribe((data: { sharesAccountData: any }) => {
|
||||
this.shareAccountData = data.sharesAccountData;
|
||||
this.dividendsData = this.shareAccountData.dividends;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.dataSource = new MatTableDataSource(this.dividendsData);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
@import "~@angular/material/theming";
|
||||
|
||||
@mixin shares-account-view-component-theme($theme) {
|
||||
$primary: map-get($theme, primary);
|
||||
mifosx-shares-account-view {
|
||||
.shares-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,119 @@
|
||||
<mat-card class="shares-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="Shares Account"
|
||||
src="assets/images/shares_account_placeholder.png">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mat-typography account-card-title">
|
||||
<mat-card-title>
|
||||
<h3>
|
||||
<i class="fa fa-stop" [ngClass]="sharesAccountData.status.code | statusLookup" [matTooltip]="sharesAccountData.status.value"></i>
|
||||
Account Name : {{sharesAccountData.productName}}
|
||||
</h3>
|
||||
</mat-card-title>
|
||||
<mat-card-subtitle>
|
||||
<p>
|
||||
Account #: {{sharesAccountData.accountNo}} | Client Name: {{sharesAccountData.clientName}}<br/>
|
||||
Current Market Price: {{sharesAccountData.currency.displaySymbol}} {{sharesAccountData.currentMarketPrice}}<br/>
|
||||
Lockin Period: {{sharesAccountData.lockinPeriod ? sharesAccountData.lockinPeriod : 'N/A'}}
|
||||
{{sharesAccountData.lockinPeriod ? sharesAccountData.lockPeriodTypeEnum.value : ''}}
|
||||
</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 *mifosxHasPermission="button.taskPermissionName">
|
||||
<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 button of buttonConfig.options">
|
||||
<button mat-menu-item *mifosxHasPermission="button.taskPermissionName">{{button.name}}</button>
|
||||
</span>
|
||||
</mat-menu>
|
||||
</ng-container>
|
||||
|
||||
</mat-card-actions>
|
||||
|
||||
</mat-card-header>
|
||||
|
||||
<mat-card-content class="content">
|
||||
|
||||
<div class="shares-account-tables" fxLayout="row" fxLayoutGap="2%">
|
||||
|
||||
<div fxFlex="49%">
|
||||
<h4 class="table-headers">Shares Details</h4>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Activated On</td>
|
||||
<td>{{sharesAccountData.timeline.activatedOnDate ? (sharesAccountData.timeline.activatedOnDate | date) : 'Not Activated'}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Currency</td>
|
||||
<td>{{sharesAccountData.currency.name}} [{{sharesAccountData.currency.code}}]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>External Id</td>
|
||||
<td>{{sharesAccountData.externalId ? sharesAccountData.externalId : 'Not Provided'}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Linked Savings Account(Dividend Posting)</td>
|
||||
<td>{{sharesAccountData.savingsAccountNumber ? sharesAccountData.savingsAccountNumber : 'Unassigned'}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div fxFlex="49%">
|
||||
<h4 class="table-headers">Account Summary</h4>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Approved Shares</td>
|
||||
<td>{{sharesAccountData.summary.totalApprovedShares}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Pending for Approval Shares</td>
|
||||
<td>{{sharesAccountData.summary.totalPendingForApprovalShares}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<nav mat-tab-nav-bar class="navigation-tabs">
|
||||
<a mat-tab-link [routerLink]="['./transactions']" routerLinkActive #transactions="routerLinkActive"
|
||||
[active]="transactions.isActive" *mifosxHasPermission="'READ_SHAREACCOUNTPURCHASE'">
|
||||
Transactions
|
||||
</a>
|
||||
<a mat-tab-link [routerLink]="['./charges']" routerLinkActive #charges="routerLinkActive"
|
||||
[active]="charges.isActive" *mifosxHasPermission="'READ_SHAREACCOUNTCHARGE'">
|
||||
Charges
|
||||
</a>
|
||||
<a mat-tab-link [routerLink]="['./dividends']" routerLinkActive #dividends="routerLinkActive"
|
||||
[active]="dividends.isActive" *mifosxHasPermission="'READ_SHAREACCOUNTDIVIDENDS'">
|
||||
Dividends
|
||||
</a>
|
||||
</nav>
|
||||
|
||||
<router-outlet></router-outlet>
|
||||
|
||||
</mat-card-content>
|
||||
|
||||
</mat-card>
|
||||
@@ -0,0 +1,53 @@
|
||||
.shares-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 {
|
||||
.shares-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 { SharesAccountViewComponent } from './shares-account-view.component';
|
||||
|
||||
describe('SharesAccountViewComponent', () => {
|
||||
let component: SharesAccountViewComponent;
|
||||
let fixture: ComponentFixture<SharesAccountViewComponent>;
|
||||
|
||||
beforeEach(async(() => {
|
||||
TestBed.configureTestingModule({
|
||||
declarations: [ SharesAccountViewComponent ]
|
||||
})
|
||||
.compileComponents();
|
||||
}));
|
||||
|
||||
beforeEach(() => {
|
||||
fixture = TestBed.createComponent(SharesAccountViewComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
||||
|
||||
it('should create', () => {
|
||||
expect(component).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,69 @@
|
||||
/** Angular Imports */
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
/** Custom Buttons Configuration */
|
||||
import { SharesButtonsConfiguration } from './shares-buttons.config';
|
||||
|
||||
/**
|
||||
* Shares Account View
|
||||
*/
|
||||
@Component({
|
||||
selector: 'mifosx-shares-account-view',
|
||||
templateUrl: './shares-account-view.component.html',
|
||||
styleUrls: ['./shares-account-view.component.scss']
|
||||
})
|
||||
export class SharesAccountViewComponent implements OnInit {
|
||||
|
||||
/** Shares Account Data */
|
||||
sharesAccountData: any;
|
||||
/** Button Configurations */
|
||||
buttonConfig: SharesButtonsConfiguration;
|
||||
|
||||
/**
|
||||
* Fetches shares account data from `resolve`
|
||||
* @param {ActivatedRoute} route Activated Route
|
||||
*/
|
||||
constructor(private route: ActivatedRoute) {
|
||||
this.route.data.subscribe((data: { sharesAccountData: any }) => {
|
||||
this.sharesAccountData = data.sharesAccountData;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.setConditionalButtons();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds options to button config. conditionaly.
|
||||
*/
|
||||
setConditionalButtons() {
|
||||
const status = this.sharesAccountData.status.value;
|
||||
this.buttonConfig = new SharesButtonsConfiguration(status);
|
||||
if (this.sharesAccountData.charges) {
|
||||
const charges: any[] = this.sharesAccountData.charges;
|
||||
charges.forEach((charge: any) => {
|
||||
if (charge.name === 'Annual fee - INR') {
|
||||
this.buttonConfig.addOption({
|
||||
name: 'Apply Anuual Fees',
|
||||
taskPermissionName: 'APPLYANNUALFEE_SAVINGSACCOUNT'
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
if (status === 'Active') {
|
||||
const purchasedShares: any[] = this.sharesAccountData.purchasedShares;
|
||||
let sharesPendingForApproval = false;
|
||||
purchasedShares.forEach((share: any) => {
|
||||
if (share.status.code === 'purchasedSharesStatusType.applied' && share.type.code === 'purchasedSharesType.purchased') {
|
||||
sharesPendingForApproval = true;
|
||||
}
|
||||
});
|
||||
if (!sharesPendingForApproval) {
|
||||
this.buttonConfig.removeButton('Approve Additional Shares');
|
||||
this.buttonConfig.removeButton('Reject Additional Shares');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
/** Shares Account Buttons Configuration */
|
||||
export class SharesButtonsConfiguration {
|
||||
|
||||
optionArray: {
|
||||
name: string,
|
||||
taskPermissionName: string,
|
||||
action?: Function
|
||||
}[];
|
||||
|
||||
buttonsArray: {
|
||||
name: string,
|
||||
icon: string,
|
||||
taskPermissionName: string,
|
||||
action?: Function
|
||||
}[];
|
||||
|
||||
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: 'Apply Additional Shares',
|
||||
icon: 'fa fa-arrow-right',
|
||||
taskPermissionName: 'APPLYADDITIONAL_SHAREACCOUNT'
|
||||
},
|
||||
{
|
||||
name: 'Approve Additional Shares',
|
||||
icon: 'fa fa-arrow-right',
|
||||
taskPermissionName: 'APPROVEADDITIONAL_SHAREACCOUNT'
|
||||
},
|
||||
{
|
||||
name: 'Reject Additional Shares',
|
||||
icon: 'fa fa-arrow-right',
|
||||
taskPermissionName: 'REJECTADDITIONAL_SHAREACCOUNT'
|
||||
},
|
||||
{
|
||||
name: 'Redeem Shares',
|
||||
icon: 'fa fa-arrow-left',
|
||||
taskPermissionName: 'WITHDRAW_SAVINGSACCOUNT'
|
||||
}
|
||||
];
|
||||
break;
|
||||
case 'Submitted and pending approval':
|
||||
this.buttonsArray = [
|
||||
{
|
||||
name: 'Modify Application',
|
||||
icon: 'fa fa-pencil ',
|
||||
taskPermissionName: 'UPDATE_SHAREACCOUNT'
|
||||
},
|
||||
{
|
||||
name: 'Approve',
|
||||
icon: 'fa fa-check',
|
||||
taskPermissionName: 'APPROVE_SHAREACCOUNT'
|
||||
}
|
||||
];
|
||||
break;
|
||||
case 'Approved':
|
||||
this.buttonsArray = [
|
||||
{
|
||||
name: 'Undo Approval',
|
||||
icon: 'fa fa-undo',
|
||||
taskPermissionName: 'APPROVALUNDO_SHAREACCOUNT'
|
||||
},
|
||||
{
|
||||
name: 'Activate',
|
||||
icon: 'fa fa-check',
|
||||
taskPermissionName: 'ACTIVATE_SHAREACCOUNT'
|
||||
}
|
||||
];
|
||||
break;
|
||||
default:
|
||||
this.buttonsArray = [];
|
||||
}
|
||||
}
|
||||
|
||||
setOptions(status: string) {
|
||||
switch (status) {
|
||||
case 'Active':
|
||||
this.optionArray = [
|
||||
{
|
||||
name: 'Close',
|
||||
taskPermissionName: 'CLOSE_SHAREACCOUNT'
|
||||
}
|
||||
];
|
||||
break;
|
||||
case 'Submitted and pending approval':
|
||||
this.optionArray = [
|
||||
{
|
||||
name: 'Reject',
|
||||
taskPermissionName: 'REJECT_SHAREACCOUNT'
|
||||
},
|
||||
{
|
||||
name: 'Delete',
|
||||
taskPermissionName: 'DELETE_SHAREACCOUNT'
|
||||
}
|
||||
];
|
||||
break;
|
||||
case 'Approved':
|
||||
default:
|
||||
this.optionArray = [];
|
||||
}
|
||||
}
|
||||
|
||||
addOption(option: {name: string, taskPermissionName: string}) {
|
||||
this.optionArray.push(option);
|
||||
}
|
||||
|
||||
removeButton(name: string) {
|
||||
const buttonNames = this.buttonsArray.map(entry => entry.name);
|
||||
const index = buttonNames.indexOf(name);
|
||||
this.buttonsArray.splice(index, 1);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
<div class="tab-container mat-typography">
|
||||
|
||||
<div class="m-b-10">
|
||||
<h3>All Transactions</h3>
|
||||
</div>
|
||||
|
||||
<div class="mat-elevation-z1 m-b-25">
|
||||
|
||||
<table mat-table [dataSource]="dataSource">
|
||||
|
||||
<ng-container matColumnDef="transactionDate">
|
||||
<th mat-header-cell *matHeaderCellDef> Transaction Date </th>
|
||||
<td mat-cell *matCellDef="let transaction"> {{transaction.purchasedDate | date}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="transactionType">
|
||||
<th mat-header-cell *matHeaderCellDef> Transaction Type </th>
|
||||
<td mat-cell *matCellDef="let transaction"> {{transaction.type.value}} {{transaction.type.value !== "Charge Payment" ? ('(' + transaction.status.value + ')') : ''}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="totalShares">
|
||||
<th mat-header-cell *matHeaderCellDef> Total Shares </th>
|
||||
<td mat-cell *matCellDef="let transaction"> {{transaction.numberOfShares}} </td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="purchasedOrRedeemedPrice">
|
||||
<th mat-header-cell *matHeaderCellDef> Purhcased/Redeemed Price </th>
|
||||
<td mat-cell *matCellDef="let transaction">{{shareAccountData.currency.displaySymbol}} {{transaction.purchasedPrice}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="chargeAmount">
|
||||
<th mat-header-cell *matHeaderCellDef> Charge Amount </th>
|
||||
<td mat-cell *matCellDef="let transaction">{{shareAccountData.currency.displaySymbol}} {{transaction.type.value === "Charge Payment" ? transaction.amount : transaction.chargeAmount}}</td>
|
||||
</ng-container>
|
||||
|
||||
<ng-container matColumnDef="amountRecievedOrReturned">
|
||||
<th mat-header-cell *matHeaderCellDef> Amount Recieved/Returned </th>
|
||||
<td mat-cell *matCellDef="let transaction">{{shareAccountData.currency.displaySymbol}} {{transaction.amount}}</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%;
|
||||
}
|
||||
}
|
||||
+25
@@ -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,47 @@
|
||||
/** 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 {
|
||||
|
||||
/** Shares Account Data */
|
||||
shareAccountData: any;
|
||||
/** Transactions Data */
|
||||
transactionsData: any;
|
||||
/** Data source for transactions table. */
|
||||
dataSource: MatTableDataSource<any>;
|
||||
/** Columns to be displayed in transactions table. */
|
||||
displayedColumns: string[] = [
|
||||
'transactionDate',
|
||||
'transactionType',
|
||||
'totalShares',
|
||||
'purchasedOrRedeemedPrice',
|
||||
'chargeAmount',
|
||||
'amountRecievedOrReturned'
|
||||
];
|
||||
|
||||
/**
|
||||
* Retrieves shares account data from `resolve`.
|
||||
* @param {ActivatedRoute} route Activated Route.
|
||||
*/
|
||||
constructor(private route: ActivatedRoute) {
|
||||
this.route.parent.data.subscribe((data: { sharesAccountData: any }) => {
|
||||
this.shareAccountData = data.sharesAccountData;
|
||||
this.transactionsData = this.shareAccountData.purchasedShares;
|
||||
});
|
||||
}
|
||||
|
||||
ngOnInit() {
|
||||
this.dataSource = new MatTableDataSource(this.transactionsData);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/** Angular Imports */
|
||||
import { NgModule } from '@angular/core';
|
||||
import { Routes, RouterModule } from '@angular/router';
|
||||
|
||||
/** Translation Imports */
|
||||
import { extract } from '../core/i18n/i18n.service';
|
||||
|
||||
/** Custom Components */
|
||||
import { SharesAccountViewComponent } from './shares-account-view/shares-account-view.component';
|
||||
import { TransactionsTabComponent } from './shares-account-view/transactions-tab/transactions-tab.component';
|
||||
import { ChargesTabComponent } from './shares-account-view/charges-tab/charges-tab.component';
|
||||
import { DividendsTabComponent } from './shares-account-view/dividends-tab/dividends-tab.component';
|
||||
|
||||
/** Custom Resolvers */
|
||||
import { SharesAccountViewResolver } from './common-resolvers/share-account-view.resolver';
|
||||
|
||||
const routes: Routes = [
|
||||
{
|
||||
path: '',
|
||||
data: { title: extract('Shares'), breadcrumb: 'Shares', routeParamBreadcrumb: false },
|
||||
children: [
|
||||
{
|
||||
path: ':shareAccountId',
|
||||
data: { title: extract('Shares Account View'), routeParamBreadcrumb: 'shareAccountId' },
|
||||
component: SharesAccountViewComponent,
|
||||
resolve: {
|
||||
sharesAccountData: SharesAccountViewResolver
|
||||
},
|
||||
children: [
|
||||
{
|
||||
path: 'transactions',
|
||||
component: TransactionsTabComponent,
|
||||
data: { title: extract('Shares Account Transactions'), breadcrumb: 'Transactions', routeParamBreadcrumb: false }
|
||||
},
|
||||
{
|
||||
path: 'charges',
|
||||
component: ChargesTabComponent,
|
||||
data: { title: extract('Shares Account Charges'), breadcrumb: 'Charges', routeParamBreadcrumb: false }
|
||||
},
|
||||
{
|
||||
path: 'dividends',
|
||||
component: DividendsTabComponent,
|
||||
data: { title: extract('Shares Account Dividends'), breadcrumb: 'Dividends', routeParamBreadcrumb: false }
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
@NgModule({
|
||||
imports: [RouterModule.forChild(routes)],
|
||||
exports: [RouterModule],
|
||||
providers: [
|
||||
SharesAccountViewResolver
|
||||
]
|
||||
})
|
||||
export class SharesRoutingModule { }
|
||||
@@ -0,0 +1,35 @@
|
||||
/** Angular Imports */
|
||||
import { NgModule } from '@angular/core';
|
||||
import { DatePipe } from '@angular/common';
|
||||
|
||||
/** Custom Modules */
|
||||
import { SharesRoutingModule } from './shares-routing.module';
|
||||
import { SharedModule } from 'app/shared/shared.module';
|
||||
import { PipesModule } from '../pipes/pipes.module';
|
||||
import { DirectivesModule } from '../directives/directives.module';
|
||||
import { SharesAccountViewComponent } from './shares-account-view/shares-account-view.component';
|
||||
import { TransactionsTabComponent } from './shares-account-view/transactions-tab/transactions-tab.component';
|
||||
import { DividendsTabComponent } from './shares-account-view/dividends-tab/dividends-tab.component';
|
||||
import { ChargesTabComponent } from './shares-account-view/charges-tab/charges-tab.component';
|
||||
|
||||
/**
|
||||
* Shares Module
|
||||
*
|
||||
* All components related to Shares functions should be declared here.
|
||||
*/
|
||||
@NgModule({
|
||||
imports: [
|
||||
SharedModule,
|
||||
PipesModule,
|
||||
DirectivesModule,
|
||||
SharesRoutingModule
|
||||
],
|
||||
declarations: [
|
||||
SharesAccountViewComponent,
|
||||
TransactionsTabComponent,
|
||||
DividendsTabComponent,
|
||||
ChargesTabComponent
|
||||
],
|
||||
providers: [DatePipe]
|
||||
})
|
||||
export class SharesModule { }
|
||||
@@ -0,0 +1,12 @@
|
||||
import { TestBed } from '@angular/core/testing';
|
||||
|
||||
import { SharesService } from './shares.service';
|
||||
|
||||
describe('SharesService', () => {
|
||||
beforeEach(() => TestBed.configureTestingModule({}));
|
||||
|
||||
it('should be created', () => {
|
||||
const service: SharesService = TestBed.get(SharesService);
|
||||
expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,26 @@
|
||||
/** Angular Imports */
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
|
||||
/** rxjs Imports */
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
/**
|
||||
* Shares Service.
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class SharesService {
|
||||
|
||||
constructor(private http: HttpClient) {}
|
||||
|
||||
/**
|
||||
* @param accountId Shares Account Id of account to get data for.
|
||||
* @returns {Observable<any>} Shares data.
|
||||
*/
|
||||
getSharesAccountData(accountId: string): Observable<any> {
|
||||
return this.http.get(`/accounts/share/${accountId}`);
|
||||
}
|
||||
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
@@ -6,6 +6,7 @@
|
||||
@import '../../app/home/dashboard/dashboard.component-theme.scss';
|
||||
@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';
|
||||
|
||||
// Custom material palette
|
||||
$mat-denim: (
|
||||
@@ -57,3 +58,4 @@ $mifosx-app-theme: mat-light-theme($mifosx-app-primary, $mifosx-app-accent, $mif
|
||||
@include dashboard-component-theme($mifosx-app-theme);
|
||||
@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);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
@import '../../app/home/dashboard/dashboard.component-theme.scss';
|
||||
@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';
|
||||
|
||||
// Custom material palette
|
||||
$mat-picton-blue: (
|
||||
@@ -57,3 +58,4 @@ $mifosx-app-theme: mat-light-theme($mifosx-app-primary, $mifosx-app-accent, $mif
|
||||
@include dashboard-component-theme($mifosx-app-theme);
|
||||
@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);
|
||||
|
||||
Reference in New Issue
Block a user