diff --git a/src/app/clients/clients-routing.module.ts b/src/app/clients/clients-routing.module.ts index 26a9bd070..9e3de6735 100644 --- a/src/app/clients/clients-routing.module.ts +++ b/src/app/clients/clients-routing.module.ts @@ -49,11 +49,6 @@ const routes: Routes = [ path: '', component: ClientsComponent, }, - { - path: ':clientId/savingsaccounts', - data: { routeParamBreadcrumb: 'clientId'}, - loadChildren: '../savings/savings.module#SavingsModule' - }, { path: ':clientId', component: ClientsViewComponent, @@ -177,7 +172,11 @@ const routes: Routes = [ path: 'loans', data: { title: extract('Loans'), breadcrumb: 'loans', routeParamBreadcrumb: false }, loadChildren: '../loans/loans.module#LoansModule' - } + }, + { + path: 'savingsaccounts', + loadChildren: '../savings/savings.module#SavingsModule' + }, ] } ] diff --git a/src/app/clients/clients-view/general-tab/general-tab.component.html b/src/app/clients/clients-view/general-tab/general-tab.component.html index 8478ff410..62e427624 100644 --- a/src/app/clients/clients-view/general-tab/general-tab.component.html +++ b/src/app/clients/clients-view/general-tab/general-tab.component.html @@ -243,7 +243,7 @@ - + diff --git a/src/app/groups/groups-routing.module.ts b/src/app/groups/groups-routing.module.ts index 6f9c7314e..8949ef702 100644 --- a/src/app/groups/groups-routing.module.ts +++ b/src/app/groups/groups-routing.module.ts @@ -47,48 +47,57 @@ const routes: Routes = [ }, { path: ':groupId', - component: GroupsViewComponent, data: { title: extract('View Group'), routeParamBreadcrumb: 'groupId' }, - resolve: { - groupViewData: GroupViewResolver, - groupDatatables: GroupDatatablesResolver - }, children: [ { - path: 'general', - component: GeneralTabComponent, - data: { title: extract('General'), breadcrumb: 'General', routeParamBreadcrumb: false }, + path: '', + component: GroupsViewComponent, resolve: { - groupAccountsData: GroupAccountsResolver, - groupSummary: GroupSummaryResolver - } - }, - { - path: 'notes', - component: NotesTabComponent, - data: { title: extract('Notes'), breadcrumb: 'Notes', routeParamBreadcrumb: false }, - resolve: { - groupNotes: GroupNotesResolver - } - }, - { - path: 'committee', - component: CommitteeTabComponent, - data: { title: extract('Committee'), breadcrumb: 'Committee', routeParamBreadcrumb: false } - }, - { - path: 'datatables', + groupViewData: GroupViewResolver, + groupDatatables: GroupDatatablesResolver + }, children: [ { - path: ':datatableName', - component: DatatableTabsComponent, - data: { title: extract('View Data Table'), routeParamBreadcrumb: 'datatableName' }, + path: 'general', + component: GeneralTabComponent, + data: { title: extract('General'), breadcrumb: 'General', routeParamBreadcrumb: false }, resolve: { - groupDatatable: GroupDatatableResolver + groupAccountsData: GroupAccountsResolver, + groupSummary: GroupSummaryResolver } + }, + { + path: 'notes', + component: NotesTabComponent, + data: { title: extract('Notes'), breadcrumb: 'Notes', routeParamBreadcrumb: false }, + resolve: { + groupNotes: GroupNotesResolver + } + }, + { + path: 'committee', + component: CommitteeTabComponent, + data: { title: extract('Committee'), breadcrumb: 'Committee', routeParamBreadcrumb: false } + }, + { + path: 'datatables', + children: [ + { + path: ':datatableName', + component: DatatableTabsComponent, + data: { title: extract('View Data Table'), routeParamBreadcrumb: 'datatableName' }, + resolve: { + groupDatatable: GroupDatatableResolver + } + } + ] } ] - } + }, + { + path: 'savingsaccounts', + loadChildren: '../savings/savings.module#SavingsModule' + }, ] } ] diff --git a/src/app/groups/groups-view/general-tab/general-tab.component.html b/src/app/groups/groups-view/general-tab/general-tab.component.html index 669b2ac33..715c53f4d 100644 --- a/src/app/groups/groups-view/general-tab/general-tab.component.html +++ b/src/app/groups/groups-view/general-tab/general-tab.component.html @@ -255,7 +255,7 @@ - + diff --git a/src/app/groups/groups-view/groups-view.component.html b/src/app/groups/groups-view/groups-view.component.html index c2b97022c..3012d916e 100644 --- a/src/app/groups/groups-view/groups-view.component.html +++ b/src/app/groups/groups-view/groups-view.component.html @@ -7,7 +7,7 @@
+ src="assets/images/group_placeholder.png">
diff --git a/src/app/groups/groups-view/groups-view.component.scss b/src/app/groups/groups-view/groups-view.component.scss index b3bd5c5cb..35c51f1fa 100644 --- a/src/app/groups/groups-view/groups-view.component.scss +++ b/src/app/groups/groups-view/groups-view.component.scss @@ -29,7 +29,7 @@ background-color: #0a6aac; p { color: white; - padding-inline: 10px; + padding: 0 10px; } } } diff --git a/src/app/home/dashboard/client-trends-bar/client-trends-bar.component.scss b/src/app/home/dashboard/client-trends-bar/client-trends-bar.component.scss index 8f272bcbc..4b7f4704d 100644 --- a/src/app/home/dashboard/client-trends-bar/client-trends-bar.component.scss +++ b/src/app/home/dashboard/client-trends-bar/client-trends-bar.component.scss @@ -7,7 +7,6 @@ } } #timescale { - margin-block: 2%; - margin-inline: 35%; + margin: 2% 35%; } } diff --git a/src/app/savings/common-resolvers/savings-account-view.resolver.ts b/src/app/savings/common-resolvers/savings-account-view.resolver.ts new file mode 100644 index 000000000..b01f4346c --- /dev/null +++ b/src/app/savings/common-resolvers/savings-account-view.resolver.ts @@ -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 { SavingsService } from '../savings.service'; + +/** + * Savings Account data resolver. + */ +@Injectable() +export class SavingsAccountViewResolver implements Resolve { + + /** + * @param {SavingsService} SavingsService Savings service. + */ + constructor(private savingsService: SavingsService) { } + + /** + * Returns the Savings Account data. + * @param {ActivatedRouteSnapshot} route Route Snapshot + * @returns {Observable} + */ + resolve(route: ActivatedRouteSnapshot): Observable { + const savingAccountId = route.paramMap.get('savingAccountId'); + return this.savingsService.getSavingsAccountData(savingAccountId); + } + +} diff --git a/src/app/savings/savings-account-view/charges-tab/charges-tab.component.html b/src/app/savings/savings-account-view/charges-tab/charges-tab.component.html new file mode 100644 index 000000000..126e58e58 --- /dev/null +++ b/src/app/savings/savings-account-view/charges-tab/charges-tab.component.html @@ -0,0 +1,106 @@ +
+ +
+
+

All Charges

+
+
+ +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Name {{ charge.name }} Fee/Penalty {{ charge.penalty === true ? 'Penalty' : 'Fee' }} Payment Due At {{ charge.chargeTimeType.value }} Due As Of {{ charge.dueDate | date }} Repeats On (M/d) {{ charge.feeOnMonthDay ? charge.feeOnMonthDay.join('/') : '' }} Calculation Type {{charge.chargeCalculationType.value}} Due {{charge.currency.displaySymbol}} {{charge.amount}} Paid {{charge.currency.displaySymbol}} {{charge.amountPaid}} Waived {{charge.currency.displaySymbol}} {{charge.amountWaived}} Outstanding {{charge.currency.displaySymbol}} {{charge.amountOutstanding}} Actions + + + + + + + + + + + +
+ +
+ +
diff --git a/src/app/savings/savings-account-view/charges-tab/charges-tab.component.scss b/src/app/savings/savings-account-view/charges-tab/charges-tab.component.scss new file mode 100644 index 000000000..aaafd7b18 --- /dev/null +++ b/src/app/savings/savings-account-view/charges-tab/charges-tab.component.scss @@ -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; + } + } +} diff --git a/src/app/savings/savings-account-view/charges-tab/charges-tab.component.spec.ts b/src/app/savings/savings-account-view/charges-tab/charges-tab.component.spec.ts new file mode 100644 index 000000000..1ef118215 --- /dev/null +++ b/src/app/savings/savings-account-view/charges-tab/charges-tab.component.spec.ts @@ -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; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ChargesTabComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ChargesTabComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/savings/savings-account-view/charges-tab/charges-tab.component.ts b/src/app/savings/savings-account-view/charges-tab/charges-tab.component.ts new file mode 100644 index 000000000..fd725011b --- /dev/null +++ b/src/app/savings/savings-account-view/charges-tab/charges-tab.component.ts @@ -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 { + + /** Savings Account Data */ + savingsAccountData: any; + /** Charges Data */ + chargesData: any[]; + /** Data source for charges table. */ + dataSource: MatTableDataSource; + /** 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; + + /** + * Retrieves Savings Account Data from `resolve`. + * @param {ActivatedRoute} route Activated Route. + */ + constructor(private route: ActivatedRoute) { + this.route.parent.data.subscribe((data: { savingsAccountData: any }) => { + this.savingsAccountData = data.savingsAccountData; + this.chargesData = this.savingsAccountData.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'; + } + +} diff --git a/src/app/savings/savings-account-view/savings-account-view.component-theme.scss b/src/app/savings/savings-account-view/savings-account-view.component-theme.scss new file mode 100644 index 000000000..c72c270e7 --- /dev/null +++ b/src/app/savings/savings-account-view/savings-account-view.component-theme.scss @@ -0,0 +1,16 @@ +@import "~@angular/material/theming"; + +@mixin savings-account-view-component-theme($theme) { + $primary: map-get($theme, primary); + mifosx-savings-account-view { + .savings-account-card { + .header { + background-color: mat-color($primary, 500); + } + .table-headers { + background-color: mat-color($primary, 500); + color: mat-contrast($primary, 500); + } + } + } +} diff --git a/src/app/savings/savings-account-view/savings-account-view.component.html b/src/app/savings/savings-account-view/savings-account-view.component.html new file mode 100644 index 000000000..59ba0b0fd --- /dev/null +++ b/src/app/savings/savings-account-view/savings-account-view.component.html @@ -0,0 +1,289 @@ + diff --git a/src/app/savings/savings-account-view/savings-account-view.component.scss b/src/app/savings/savings-account-view/savings-account-view.component.scss new file mode 100644 index 000000000..56beb2cfc --- /dev/null +++ b/src/app/savings/savings-account-view/savings-account-view.component.scss @@ -0,0 +1,53 @@ +.savings-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 { + .savings-account-tables { + padding: 1%; + margin: 1%; + .table-headers { + margin: 0; + padding: 6px; + } + td { + padding: 3px; + } + } + } + i, img:hover { + cursor: pointer; + } +} diff --git a/src/app/savings/savings-account-view/savings-account-view.component.spec.ts b/src/app/savings/savings-account-view/savings-account-view.component.spec.ts new file mode 100644 index 000000000..74fa6f85d --- /dev/null +++ b/src/app/savings/savings-account-view/savings-account-view.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SavingsAccountViewComponent } from './savings-account-view.component'; + +describe('SavingsAccountViewComponent', () => { + let component: SavingsAccountViewComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ SavingsAccountViewComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SavingsAccountViewComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/savings/savings-account-view/savings-account-view.component.ts b/src/app/savings/savings-account-view/savings-account-view.component.ts new file mode 100644 index 000000000..2dd2a2f46 --- /dev/null +++ b/src/app/savings/savings-account-view/savings-account-view.component.ts @@ -0,0 +1,84 @@ +/** Angular Imports */ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; +import { SavingsButtonsConfiguration } from './savings-buttons.config'; + +/** + * Savings Account View Component + */ +@Component({ + selector: 'mifosx-savings-account-view', + templateUrl: './savings-account-view.component.html', + styleUrls: ['./savings-account-view.component.scss'] +}) +export class SavingsAccountViewComponent implements OnInit { + + /** Savings Account Data */ + savingsAccountData: any; + /** Button Configurations */ + buttonConfig: SavingsButtonsConfiguration; + + /** + * Fetches savings account data from `resolve` + * @param {ActivatedRoute} route Activated Route + */ + constructor(private route: ActivatedRoute) { + this.route.data.subscribe((data: { savingsAccountData: any }) => { + this.savingsAccountData = data.savingsAccountData; + }); + } + + ngOnInit() { + this.setConditionalButtons(); + } + + /** + * Adds options to button config. conditionaly. + */ + setConditionalButtons() { + const status = this.savingsAccountData.status.value; + this.buttonConfig = new SavingsButtonsConfiguration(status); + if (this.savingsAccountData.clientId) { + this.buttonConfig.addOption({ + name: 'Transfer Funds', + taskPermissionName: 'CREATE_ACCOUNTTRANSFER' + }); + } + if (!this.savingsAccountData.fieldOfficerId) { + this.buttonConfig.addOption({ + name: 'Assign Staff', + taskPermissionName: 'UPDATESAVINGSOFFICER_SAVINGSACCOUNT' + }); + } else { + this.buttonConfig.addOption({ + name: 'Unassign Staff', + taskPermissionName: 'REMOVESAVINGSOFFICER_SAVINGSACCOUNT' + }); + } + if (this.savingsAccountData.charges) { + const charges: any[] = this.savingsAccountData.charges; + charges.forEach((charge: any) => { + if (charge.name === 'Annual fee - INR') { + this.buttonConfig.addOption({ + name: 'Apply Anuual Fees', + taskPermissionName: 'APPLYANNUALFEE_SAVINGSACCOUNT' + }); + } + }); + } + if (this.savingsAccountData.taxGroup) { + if (this.savingsAccountData.withHoldTax) { + this.buttonConfig.addOption({ + name: 'Disable Withhold Tax', + taskPermissionName: 'UPDATEWITHHOLDTAX_SAVINGSACCOUNT' + }); + } else { + this.buttonConfig.addOption({ + name: 'Enable Withhold Tax', + taskPermissionName: 'UPDATEWITHHOLDTAX_SAVINGSACCOUNT' + }); + } + } + } + +} diff --git a/src/app/savings/savings-account-view/savings-buttons.config.ts b/src/app/savings/savings-account-view/savings-buttons.config.ts new file mode 100644 index 000000000..85eea50b4 --- /dev/null +++ b/src/app/savings/savings-account-view/savings-buttons.config.ts @@ -0,0 +1,142 @@ +/** Savings Account Buttons Configuration */ +export class SavingsButtonsConfiguration { + + 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: 'Post Interest As On', + icon: 'fa fa-arrow-right', + taskPermissionName: 'POSTINTEREST_SAVINGSACCOUNT', + }, + { + name: 'Deposit', + icon: 'fa fa-arrow-up', + taskPermissionName: 'DEPOSIT_SAVINGSACCOUNT' + }, + { + name: 'Withdraw', + icon: 'fa fa-arrow-down', + taskPermissionName: 'WITHDRAW_SAVINGSACCOUNT' + }, + { + name: 'Calculate Interest', + icon: 'fa fa-table', + taskPermissionName: 'CALCULATEINTEREST_SAVINGSACCOUNT' + } + ]; + break; + case 'Submitted and pending approval': + this.buttonsArray = [ + { + name: 'Modify Application', + icon: 'fa fa-pencil ', + taskPermissionName: 'UPDATE_SAVINGSACCOUNT' + }, + { + name: 'Approve', + icon: 'fa fa-check', + taskPermissionName: 'APPROVE_SAVINGSACCOUNT' + } + ]; + break; + case 'Approved': + this.buttonsArray = [ + { + name: 'Undo Approval', + icon: 'fa fa-undo', + taskPermissionName: 'APPROVALUNDO_SAVINGSACCOUNT' + }, + { + name: 'Activate', + icon: 'fa fa-check', + taskPermissionName: 'ACTIVATE_SAVINGSACCOUNT' + }, + { + name: 'Add Charge', + icon: 'fa fa-plus', + taskPermissionName: 'CREATE_SAVINGSACCOUNTCHARGE' + } + ]; + break; + default: + this.buttonsArray = []; + } + } + + setOptions(status: string) { + switch (status) { + case 'Active': + this.optionArray = [ + { + name: 'Post Interest', + taskPermissionName: 'POSTINTEREST_SAVINGSACCOUNT' + }, + { + name: 'Add Charge', + taskPermissionName: 'CREATE_SAVINGSACCOUNTCHARGE' + }, + { + name: 'Close', + taskPermissionName: 'CLOSE_SAVINGSACCOUNT' + } + ]; + break; + case 'Submitted and pending approval': + this.optionArray = [ + { + name: 'Reject', + taskPermissionName: 'REJECT_SAVINGSACCOUNT' + }, + { + name: 'Withdraw', + taskPermissionName: 'WITHDRAW_SAVINGSACCOUNT' + }, + { + name: 'Add Charge', + taskPermissionName: 'CREATE_SAVINGSACCOUNTCHARGE' + }, + { + name: 'Delete', + taskPermissionName: 'DELETE_SAVINGSACCOUNT' + } + ]; + break; + case 'Approved': + default: + this.optionArray = []; + } + } + + addOption(option: {name: string, taskPermissionName: string}) { + this.optionArray.push(option); + } + +} diff --git a/src/app/savings/savings-account-view/standing-instructions-tab/standing-instructions-tab.component.html b/src/app/savings/savings-account-view/standing-instructions-tab/standing-instructions-tab.component.html new file mode 100644 index 000000000..709466062 --- /dev/null +++ b/src/app/savings/savings-account-view/standing-instructions-tab/standing-instructions-tab.component.html @@ -0,0 +1,70 @@ +
+ +
+

All Standing Instructions

+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Client {{instruction.fromClient.displayName}}-{{instruction.fromClient.id}} From Account {{instruction.fromAccount.accountNo}} ({{instruction.fromAccountType.value}}) Beneficiary {{instruction.toClient.displayName}} To Account {{instruction.toAccount.accountNo}} ({{instruction.toAccountType.value}}) Amount {{instruction.instructionType.value}}/{{instruction.amount}} Validity {{instruction.validFrom | date}} to {{instruction.validTill | date}} Actions + + + + + + + +
+ +
+ +
diff --git a/src/app/savings/savings-account-view/standing-instructions-tab/standing-instructions-tab.component.scss b/src/app/savings/savings-account-view/standing-instructions-tab/standing-instructions-tab.component.scss new file mode 100644 index 000000000..aaafd7b18 --- /dev/null +++ b/src/app/savings/savings-account-view/standing-instructions-tab/standing-instructions-tab.component.scss @@ -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; + } + } +} diff --git a/src/app/savings/savings-account-view/standing-instructions-tab/standing-instructions-tab.component.spec.ts b/src/app/savings/savings-account-view/standing-instructions-tab/standing-instructions-tab.component.spec.ts new file mode 100644 index 000000000..f3997e094 --- /dev/null +++ b/src/app/savings/savings-account-view/standing-instructions-tab/standing-instructions-tab.component.spec.ts @@ -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; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ StandingInstructionsTabComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(StandingInstructionsTabComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/savings/savings-account-view/standing-instructions-tab/standing-instructions-tab.component.ts b/src/app/savings/savings-account-view/standing-instructions-tab/standing-instructions-tab.component.ts new file mode 100644 index 000000000..5d6421466 --- /dev/null +++ b/src/app/savings/savings-account-view/standing-instructions-tab/standing-instructions-tab.component.ts @@ -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 { SavingsService } from 'app/savings/savings.service'; + +/** + * Savings 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 { + + /** Savings Data */ + savingsData: 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; + + /** + * Retrieves Savings Account Data from `resolve`. + * @param {ActivatedRoute} route Activated Route. + */ + constructor(private route: ActivatedRoute, + private savingsService: SavingsService) { + this.route.parent.data.subscribe((data: { savingsAccountData: any }) => { + this.savingsData = data.savingsAccountData; + }); + } + + ngOnInit() { + this.getStandingInstructions(); + } + + /** + * Retrieves standing instructions and initializes instructions table. + */ + getStandingInstructions() { + const clientId = this.savingsData.clientId; + const clientName = this.savingsData.clientName; + const accountId = this.savingsData.id; + const locale = 'en'; + const dateFormat = 'dd MMMM yyyy'; + this.savingsService.getStandingInstructions(clientId, clientName, accountId, locale, dateFormat).subscribe((response: any) => { + this.instructionsData = response.pageItems; + this.dataSource.data = this.instructionsData; + this.instructionTableRef.renderRows(); + }); + } + +} diff --git a/src/app/savings/savings-account-view/transactions-tab/transactions-tab.component.html b/src/app/savings/savings-account-view/transactions-tab/transactions-tab.component.html new file mode 100644 index 000000000..1be786c3b --- /dev/null +++ b/src/app/savings/savings-account-view/transactions-tab/transactions-tab.component.html @@ -0,0 +1,63 @@ +
+ +
+
+

All Transactions

+
+
+ + +
+
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ID {{ transaction.id }} Transaction Date {{ transaction.date | date }} Transaction Type {{ transaction.transactionType.value }} Debit {{ isDebit(transaction.transactionType) ? transaction.amount : 'N/A'}} Credit {{ !isDebit(transaction.transactionType) ? transaction.amount : 'N/A' }} Balance {{ transaction.runningBalance }} View Reciept + +
+ +
+ +
diff --git a/src/app/savings/savings-account-view/transactions-tab/transactions-tab.component.scss b/src/app/savings/savings-account-view/transactions-tab/transactions-tab.component.scss new file mode 100644 index 000000000..ad2bc9bd7 --- /dev/null +++ b/src/app/savings/savings-account-view/transactions-tab/transactions-tab.component.scss @@ -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 0 3px 0; + margin: 0 10%; + line-height: 25px; + } + } +} diff --git a/src/app/savings/savings-account-view/transactions-tab/transactions-tab.component.spec.ts b/src/app/savings/savings-account-view/transactions-tab/transactions-tab.component.spec.ts new file mode 100644 index 000000000..a67fc2279 --- /dev/null +++ b/src/app/savings/savings-account-view/transactions-tab/transactions-tab.component.spec.ts @@ -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; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ TransactionsTabComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(TransactionsTabComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/savings/savings-account-view/transactions-tab/transactions-tab.component.ts b/src/app/savings/savings-account-view/transactions-tab/transactions-tab.component.ts new file mode 100644 index 000000000..d6d68d3ae --- /dev/null +++ b/src/app/savings/savings-account-view/transactions-tab/transactions-tab.component.ts @@ -0,0 +1,60 @@ +/** 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 { + + /** Savings Account Status */ + status: any; + /** Transactions Data */ + transactionsData: any; + /** Columns to be displayed in transactions table. */ + displayedColumns: string[] = ['id', 'transactionDate', 'transactionType', 'debit', 'credit', 'balance', 'viewReciept']; + /** Data source for transactions table. */ + dataSource: MatTableDataSource; + + /** + * Retrieves savings account data from `resolve`. + * @param {ActivatedRoute} route Activated Route. + */ + constructor(private route: ActivatedRoute) { + this.route.parent.data.subscribe((data: { savingsAccountData: any }) => { + this.transactionsData = data.savingsAccountData.transactions; + this.status = data.savingsAccountData.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; + } + + /** + * Checks transaction status. + */ + checkStatus() { + if (this.status === 'Active' || this.status === 'Closed' || this.status === 'Transfer in progress' || + this.status === 'Transfer on hold' || this.status === 'Premature Closed' || this.status === 'Matured') { + return true; + } + return false; + } + +} diff --git a/src/app/savings/savings-routing.module.ts b/src/app/savings/savings-routing.module.ts index 387d93dd7..f1159ae59 100644 --- a/src/app/savings/savings-routing.module.ts +++ b/src/app/savings/savings-routing.module.ts @@ -6,32 +6,50 @@ import { Routes, RouterModule } from '@angular/router'; import { extract } from '../core/i18n/i18n.service'; /** Custom Components */ +import { SavingsAccountViewComponent } from './savings-account-view/savings-account-view.component'; +import { TransactionsTabComponent } from './savings-account-view/transactions-tab/transactions-tab.component'; import { SavingAccountActionsComponent } from './saving-account-actions/saving-account-actions.component'; import { AddSavingsChargeComponent } from './add-savings-charge/add-savings-charge.component'; +import { ChargesTabComponent } from './savings-account-view/charges-tab/charges-tab.component'; +import { StandingInstructionsTabComponent } from './savings-account-view/standing-instructions-tab/standing-instructions-tab.component'; /** Custom Resolvers */ import { SavingAccountTransactionTemplateResolver } from './common-resolvers/saving-transaction-template.resolver'; import { SavingsChargeTemplateResolver } from './common-resolvers/savings-charge-template.resolver'; +import { SavingsAccountViewResolver } from './common-resolvers/savings-account-view.resolver'; const routes: Routes = [ { path: '', data: { title: extract('All Savings'), breadcrumb: 'Savings', routeParamBreadcrumb: false }, - // Component to view all saving accounts Comes Here children: [ { path: ':savingAccountId', data: { title: extract('Saving Account View'), routeParamBreadcrumb: 'savingAccountId' }, - // Component For Saving Account View Comes Here + component: SavingsAccountViewComponent, + resolve: { + savingsAccountData: SavingsAccountViewResolver + }, children: [ + { + path: 'transactions', + component: TransactionsTabComponent, + data: { title: extract('Savings Account Transactions'), breadcrumb: 'Transactions', routeParamBreadcrumb: false } + }, + { + path: 'charges', + component: ChargesTabComponent, + data: { title: extract('Savings Account Charges'), breadcrumb: 'Charges', routeParamBreadcrumb: false } + }, + { + path: 'standing-instructions', + component: StandingInstructionsTabComponent, + data: { title: extract('Savings Account SIH'), breadcrumb: 'Standing Instructions', routeParamBreadcrumb: false } + }, { path: 'add-savings-charge', component: AddSavingsChargeComponent, - data: { - title: extract('Add Savings Charge'), - breadcrumb: 'Add Savings Charge', - routeParamBreadcrumb: false - }, + data: { title: extract('Add Savings Charge'), breadcrumb: 'Add Savings Charge', routeParamBreadcrumb: false }, resolve: { savingsChargeTemplate: SavingsChargeTemplateResolver } @@ -53,6 +71,8 @@ const routes: Routes = [ imports: [RouterModule.forChild(routes)], exports: [RouterModule], declarations: [], - providers: [SavingAccountTransactionTemplateResolver, SavingsChargeTemplateResolver] + providers: [SavingAccountTransactionTemplateResolver, + SavingsChargeTemplateResolver, + SavingsAccountViewResolver] }) export class SavingsRoutingModule {} diff --git a/src/app/savings/savings.module.ts b/src/app/savings/savings.module.ts index 3cabcde2d..5d616427f 100644 --- a/src/app/savings/savings.module.ts +++ b/src/app/savings/savings.module.ts @@ -5,11 +5,17 @@ import { DatePipe } from '@angular/common'; /** Custom Modules */ import { SavingsRoutingModule } from './savings-routing.module'; import { SharedModule } from 'app/shared/shared.module'; +import { PipesModule } from '../pipes/pipes.module'; +import { DirectivesModule } from '../directives/directives.module'; /** Custom Components */ import { SavingAccountActionsComponent } from './saving-account-actions/saving-account-actions.component'; import { SavingsAccountTransactionsComponent } from './saving-account-actions/savings-account-transactions/savings-account-transactions.component'; import { AddSavingsChargeComponent } from './add-savings-charge/add-savings-charge.component'; +import { TransactionsTabComponent } from './savings-account-view/transactions-tab/transactions-tab.component'; +import { SavingsAccountViewComponent } from './savings-account-view/savings-account-view.component'; +import { ChargesTabComponent } from './savings-account-view/charges-tab/charges-tab.component'; +import { StandingInstructionsTabComponent } from './savings-account-view/standing-instructions-tab/standing-instructions-tab.component'; /** * Savings Module @@ -19,12 +25,18 @@ import { AddSavingsChargeComponent } from './add-savings-charge/add-savings-char @NgModule({ imports: [ SharedModule, + PipesModule, + DirectivesModule, SavingsRoutingModule ], declarations: [ SavingAccountActionsComponent, SavingsAccountTransactionsComponent, - AddSavingsChargeComponent + AddSavingsChargeComponent, + TransactionsTabComponent, + SavingsAccountViewComponent, + ChargesTabComponent, + StandingInstructionsTabComponent ], providers: [DatePipe] }) diff --git a/src/app/savings/savings.service.ts b/src/app/savings/savings.service.ts index 59cc011b9..4b3db6dd9 100644 --- a/src/app/savings/savings.service.ts +++ b/src/app/savings/savings.service.ts @@ -1,6 +1,6 @@ /** Angular Imports */ import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; +import { HttpClient, HttpParams } from '@angular/common/http'; /** rxjs Imports */ import { Observable } from 'rxjs'; @@ -12,7 +12,9 @@ import { Observable } from 'rxjs'; providedIn: 'root' }) export class SavingsService { + constructor(private http: HttpClient) {} + /** * @param {string} savingAccountId is saving account's Id. * @returns {Observable} @@ -55,4 +57,35 @@ export class SavingsService { const params = { template: 'true' }; return this.http.get(`/charges/${chargeId}`, { params: params }); } + + /** + * @param groupId Group Id of group to get data for. + * @returns {Observable} Group data. + */ + getSavingsAccountData(accountId: string): Observable { + const httpParams = new HttpParams().set('associations', 'all'); + return this.http.get(`/savingsaccounts/${accountId}`, { params: httpParams }); + } + + /** + * @param clientId Client Id + * @param clientName Client Name + * @param fromAccountId Account Id + * @param locale Locale + * @param dateFormat Date Format + * @returns {Observable} Standing Instructions + */ + getStandingInstructions( + clientId: string, clientName: string, fromAccountId: string, + locale: string, dateFormat: string): Observable { + 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 }); + } + } diff --git a/src/assets/images/savings_account_placeholder.png b/src/assets/images/savings_account_placeholder.png new file mode 100644 index 000000000..b45fe9be0 Binary files /dev/null and b/src/assets/images/savings_account_placeholder.png differ diff --git a/src/theme/custom/denim-yellowgreen.scss b/src/theme/custom/denim-yellowgreen.scss index 221893882..21610548f 100644 --- a/src/theme/custom/denim-yellowgreen.scss +++ b/src/theme/custom/denim-yellowgreen.scss @@ -5,6 +5,7 @@ @import '../../app/centers/centers-view/centers-view.component-theme.scss'; @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'; // Custom material palette $mat-denim: ( @@ -55,3 +56,4 @@ $mifosx-app-theme: mat-light-theme($mifosx-app-primary, $mifosx-app-accent, $mif @include centers-view-component-theme($mifosx-app-theme); @include dashboard-component-theme($mifosx-app-theme); @include loans-view-component-theme($mifosx-app-theme); +@include savings-account-view-component-theme($mifosx-app-theme); diff --git a/src/theme/custom/pictonblue-yellowgreen.scss b/src/theme/custom/pictonblue-yellowgreen.scss index 1d3067e79..c5cff6de2 100644 --- a/src/theme/custom/pictonblue-yellowgreen.scss +++ b/src/theme/custom/pictonblue-yellowgreen.scss @@ -5,6 +5,7 @@ @import '../../app/centers/centers-view/centers-view.component-theme.scss'; @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'; // Custom material palette $mat-picton-blue: ( @@ -55,3 +56,4 @@ $mifosx-app-theme: mat-light-theme($mifosx-app-primary, $mifosx-app-accent, $mif @include centers-view-component-theme($mifosx-app-theme); @include dashboard-component-theme($mifosx-app-theme); @include loans-view-component-theme($mifosx-app-theme); +@include savings-account-view-component-theme($mifosx-app-theme);