From f2a19708b7841cbe199cd469634c9403eddd003a Mon Sep 17 00:00:00 2001 From: Jivjyot Singh Date: Thu, 7 May 2020 02:27:28 +0530 Subject: [PATCH] feat: add saving-deposit and withdrawal page (#389) - Add Savings Module. - Add saving-account-actions component. - Add savings-account-transactions component. - Add savings-routing.module.ts - Add savings-transaction-template.resolver.ts Fixes: #249 --- .../saving-transaction-template.resolver.ts | 30 +++++ .../saving-account-actions.component.html | 5 + .../saving-account-actions.component.scss | 0 .../saving-account-actions.component.spec.ts | 25 ++++ .../saving-account-actions.component.ts | 26 ++++ ...avings-account-transactions.component.html | 83 ++++++++++++ ...avings-account-transactions.component.scss | 3 + ...ngs-account-transactions.component.spec.ts | 25 ++++ .../savings-account-transactions.component.ts | 122 ++++++++++++++++++ src/app/savings/savings-routing.module.ts | 44 +++++++ src/app/savings/savings.module.spec.ts | 13 ++ src/app/savings/savings.module.ts | 29 +++++ src/app/savings/savings.service.spec.ts | 12 ++ src/app/savings/savings.service.ts | 34 +++++ 14 files changed, 451 insertions(+) create mode 100644 src/app/savings/common-resolvers/saving-transaction-template.resolver.ts create mode 100644 src/app/savings/saving-account-actions/saving-account-actions.component.html create mode 100644 src/app/savings/saving-account-actions/saving-account-actions.component.scss create mode 100644 src/app/savings/saving-account-actions/saving-account-actions.component.spec.ts create mode 100644 src/app/savings/saving-account-actions/saving-account-actions.component.ts create mode 100644 src/app/savings/saving-account-actions/savings-account-transactions/savings-account-transactions.component.html create mode 100644 src/app/savings/saving-account-actions/savings-account-transactions/savings-account-transactions.component.scss create mode 100644 src/app/savings/saving-account-actions/savings-account-transactions/savings-account-transactions.component.spec.ts create mode 100644 src/app/savings/saving-account-actions/savings-account-transactions/savings-account-transactions.component.ts create mode 100644 src/app/savings/savings-routing.module.ts create mode 100644 src/app/savings/savings.module.spec.ts create mode 100644 src/app/savings/savings.module.ts create mode 100644 src/app/savings/savings.service.spec.ts create mode 100644 src/app/savings/savings.service.ts diff --git a/src/app/savings/common-resolvers/saving-transaction-template.resolver.ts b/src/app/savings/common-resolvers/saving-transaction-template.resolver.ts new file mode 100644 index 000000000..9ba849cff --- /dev/null +++ b/src/app/savings/common-resolvers/saving-transaction-template.resolver.ts @@ -0,0 +1,30 @@ +/** 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 Transaction Template data resolver. + */ +@Injectable() +export class SavingAccountTransactionTemplateResolver implements Resolve { + + /** + * @param {SavingsService} savingsService Savings service. + */ + constructor(private savingsService: SavingsService) { } + + /** + * Returns the Savings Account Transaction Template. + * @returns {Observable} + */ + resolve(route: ActivatedRouteSnapshot): Observable { + const savingAccountId = route.paramMap.get('savingAccountId'); + return this.savingsService.getSavingsTransactionTemplateResource(savingAccountId); + } +} diff --git a/src/app/savings/saving-account-actions/saving-account-actions.component.html b/src/app/savings/saving-account-actions/saving-account-actions.component.html new file mode 100644 index 000000000..7e9976138 --- /dev/null +++ b/src/app/savings/saving-account-actions/saving-account-actions.component.html @@ -0,0 +1,5 @@ +
+ + + +
diff --git a/src/app/savings/saving-account-actions/saving-account-actions.component.scss b/src/app/savings/saving-account-actions/saving-account-actions.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/savings/saving-account-actions/saving-account-actions.component.spec.ts b/src/app/savings/saving-account-actions/saving-account-actions.component.spec.ts new file mode 100644 index 000000000..efd0c542f --- /dev/null +++ b/src/app/savings/saving-account-actions/saving-account-actions.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SavingAccountActionsComponent } from './saving-account-actions.component'; + +describe('SavingAccountActionsComponent', () => { + let component: SavingAccountActionsComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ SavingAccountActionsComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SavingAccountActionsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/savings/saving-account-actions/saving-account-actions.component.ts b/src/app/savings/saving-account-actions/saving-account-actions.component.ts new file mode 100644 index 000000000..af1cc2241 --- /dev/null +++ b/src/app/savings/saving-account-actions/saving-account-actions.component.ts @@ -0,0 +1,26 @@ +/** Angular Imports */ +import { Component } from '@angular/core'; +import { Router, ActivatedRoute } from '@angular/router'; + +/** + * Create savings account actions component. + */ +@Component({ + selector: 'mifosx-saving-account-actions', + templateUrl: './saving-account-actions.component.html', + styleUrls: ['./saving-account-actions.component.scss'] +}) +export class SavingAccountActionsComponent { + + /** flag object to store possible actions and render appropriate UI to the user */ + actions: { transaction: boolean } = { transaction: false }; + + constructor(private router: Router, + private route: ActivatedRoute) { + this.route.params.subscribe(params => { + this.actions[params['action']] = true; + }); + } + + +} diff --git a/src/app/savings/saving-account-actions/savings-account-transactions/savings-account-transactions.component.html b/src/app/savings/saving-account-actions/savings-account-transactions/savings-account-transactions.component.html new file mode 100644 index 000000000..efa867a14 --- /dev/null +++ b/src/app/savings/saving-account-actions/savings-account-transactions/savings-account-transactions.component.html @@ -0,0 +1,83 @@ +
+

Withdraw Money From Saving Account

+

Deposit Money To Saving Account

+ +
+ + + + + Transaction Date + + + + + Transaction Date is required + + + + + Transaction Amount + + + Transaction Amount is required + + + + + Payment Type + + + {{ paymentType.name }} + + + + +
+ Show Payment Details + +
+ + + + Account Number + + + + + Cheque + + + + + Routing Code + + + + + Receipt Number + + + + + Bank + + + + + + Notes + + + + + + + + +
+
+
diff --git a/src/app/savings/saving-account-actions/savings-account-transactions/savings-account-transactions.component.scss b/src/app/savings/saving-account-actions/savings-account-transactions/savings-account-transactions.component.scss new file mode 100644 index 000000000..5f97c79c5 --- /dev/null +++ b/src/app/savings/saving-account-actions/savings-account-transactions/savings-account-transactions.component.scss @@ -0,0 +1,3 @@ +.container{ + width: 70%; +} diff --git a/src/app/savings/saving-account-actions/savings-account-transactions/savings-account-transactions.component.spec.ts b/src/app/savings/saving-account-actions/savings-account-transactions/savings-account-transactions.component.spec.ts new file mode 100644 index 000000000..10846aba5 --- /dev/null +++ b/src/app/savings/saving-account-actions/savings-account-transactions/savings-account-transactions.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { SavingsAccountTransactionsComponent } from './savings-account-transactions.component'; + +describe('TransactionsComponent', () => { + let component: SavingsAccountTransactionsComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ SavingsAccountTransactionsComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SavingsAccountTransactionsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/savings/saving-account-actions/savings-account-transactions/savings-account-transactions.component.ts b/src/app/savings/saving-account-actions/savings-account-transactions/savings-account-transactions.component.ts new file mode 100644 index 000000000..dcb39868d --- /dev/null +++ b/src/app/savings/saving-account-actions/savings-account-transactions/savings-account-transactions.component.ts @@ -0,0 +1,122 @@ +/** Angular Imports */ +import { Component, OnInit } from '@angular/core'; +import { FormGroup, FormBuilder, Validators, FormControl } from '@angular/forms'; +import { Router, ActivatedRoute } from '@angular/router'; +import { DatePipe } from '@angular/common'; + +/** Custom Services */ +import { SavingsService } from '../../savings.service'; + +/** + * Create savings account transactions component. + */ +@Component({ + selector: 'mifosx-savings-transactions', + templateUrl: './savings-account-transactions.component.html', + styleUrls: ['./savings-account-transactions.component.scss'] +}) +export class SavingsAccountTransactionsComponent implements OnInit { + + /** Minimum Due Date allowed. */ + minDate = new Date(2000, 0, 1); + /** Maximum Due Date allowed. */ + maxDate = new Date(); + /** Savings account transaction form. */ + savingAccountTransactionForm: FormGroup; + /** savings account transaction payment options. */ + paymentTypeOptions: { + id: number, + name: string, + description: string, + isCashPayment: boolean, + position: number + }[]; + /** Flag to enable payment details fields. */ + addPaymentDetailsFlag: Boolean = false; + /** transaction type flag to render required UI */ + transactionType: { deposit: boolean, withdrawal: boolean } = { deposit: false, withdrawal: false }; + /** transaction command for submit request */ + transactionCommand: string; + /** saving account's Id */ + savingAccountId: string; + + /** + * Retrieves the Saving Account transaction template data from `resolve`. + * @param {FormBuilder} formBuilder Form Builder. + * @param {SavingsService} savingsService Savings Service. + * @param {ActivatedRoute} route Activated Route. + * @param {DatePipe} datePipe DatePipe. + * @param {Router} router Router for navigation. + */ + constructor(private formBuilder: FormBuilder, + private route: ActivatedRoute, + private router: Router, + private datePipe: DatePipe, + private savingsService: SavingsService) { + this.route.data.subscribe((data: { savingAccountTransactionTemplate: any }) => { + this.paymentTypeOptions = data.savingAccountTransactionTemplate.paymentTypeOptions; + }); + } + + /** + * Creates the Saving account transaction form when component loads. + */ + ngOnInit() { + this.route.queryParams.subscribe(params => { + this.transactionType[params.type] = true; + this.transactionCommand = params.type; + }); + this.savingAccountId = this.route.snapshot.params['savingAccountId']; + this.createSavingAccountTransactionForm(); + } + + /** + * Method to create the Saving Account Transaction Form. + */ + createSavingAccountTransactionForm() { + this.savingAccountTransactionForm = this.formBuilder.group({ + 'transactionDate': ['', Validators.required], + 'transactionAmount': ['', Validators.required], + 'paymentTypeId': [''], + 'note': [''] + }); + } + + /** + * Method to add payment detail fields to the UI. + */ + addPaymentDetails() { + this.addPaymentDetailsFlag = !this.addPaymentDetailsFlag; + if (this.addPaymentDetailsFlag) { + this.savingAccountTransactionForm.addControl('accountNumber', new FormControl('')); + this.savingAccountTransactionForm.addControl('checkNumber', new FormControl('')); + this.savingAccountTransactionForm.addControl('routingCode', new FormControl('')); + this.savingAccountTransactionForm.addControl('receiptNumber', new FormControl('')); + this.savingAccountTransactionForm.addControl('bankNumber', new FormControl('')); + } else { + this.savingAccountTransactionForm.removeControl('accountNumber'); + this.savingAccountTransactionForm.removeControl('checkNumber'); + this.savingAccountTransactionForm.removeControl('routingCode'); + this.savingAccountTransactionForm.removeControl('receiptNumber'); + this.savingAccountTransactionForm.removeControl('bankNumber'); + } + } + + /** + * Method to submit the transaction details. + */ + submit() { + const prevTransactionDate: Date = this.savingAccountTransactionForm.value.transactionDate; + // TODO: Update once language and date settings are setup + const dateFormat = 'dd-MM-yyyy'; + this.savingAccountTransactionForm.patchValue({ + transactionDate: this.datePipe.transform(prevTransactionDate, dateFormat) + }); + const transactionData = this.savingAccountTransactionForm.value; + transactionData.locale = 'en'; + transactionData.dateFormat = dateFormat; + this.savingsService.makeTransaction(this.transactionCommand, this.savingAccountId, transactionData).subscribe(res => { + this.router.navigate(['../'], { relativeTo: this.route }); + }); + } +} diff --git a/src/app/savings/savings-routing.module.ts b/src/app/savings/savings-routing.module.ts new file mode 100644 index 000000000..e01a17386 --- /dev/null +++ b/src/app/savings/savings-routing.module.ts @@ -0,0 +1,44 @@ +/** 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 { SavingAccountActionsComponent } from './saving-account-actions/saving-account-actions.component'; + +/** Custom Resolvers */ +import { SavingAccountTransactionTemplateResolver } from './common-resolvers/saving-transaction-template.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 + children: [ + { + path: ':action', + component: SavingAccountActionsComponent, + data: { title: extract('Saving Account Actions'), routeParamBreadcrumb: 'action' }, + resolve: { + savingAccountTransactionTemplate: SavingAccountTransactionTemplateResolver + } + } + ] + } + ] + } +]; +@NgModule({ + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], + declarations: [], + providers: [SavingAccountTransactionTemplateResolver] +}) +export class SavingsRoutingModule { } diff --git a/src/app/savings/savings.module.spec.ts b/src/app/savings/savings.module.spec.ts new file mode 100644 index 000000000..2c5824bdf --- /dev/null +++ b/src/app/savings/savings.module.spec.ts @@ -0,0 +1,13 @@ +import { SavingsModule } from './savings.module'; + +describe('SavingsModule', () => { + let savingsModule: SavingsModule; + + beforeEach(() => { + savingsModule = new SavingsModule(); + }); + + it('should create an instance', () => { + expect(savingsModule).toBeTruthy(); + }); +}); diff --git a/src/app/savings/savings.module.ts b/src/app/savings/savings.module.ts new file mode 100644 index 000000000..e85124628 --- /dev/null +++ b/src/app/savings/savings.module.ts @@ -0,0 +1,29 @@ +/** Angular Imports */ +import { NgModule } from '@angular/core'; +import { DatePipe } from '@angular/common'; + +/** Custom Modules */ +import { SavingsRoutingModule } from './savings-routing.module'; +import { SharedModule } from 'app/shared/shared.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'; + +/** + * Savings Module + * + * All components related to Savings functions should be declared here. + */ +@NgModule({ + imports: [ + SharedModule, + SavingsRoutingModule + ], + declarations: [ + SavingAccountActionsComponent, + SavingsAccountTransactionsComponent + ], + providers: [DatePipe] +}) +export class SavingsModule { } diff --git a/src/app/savings/savings.service.spec.ts b/src/app/savings/savings.service.spec.ts new file mode 100644 index 000000000..cdc0fb225 --- /dev/null +++ b/src/app/savings/savings.service.spec.ts @@ -0,0 +1,12 @@ +import { TestBed } from '@angular/core/testing'; + +import { SavingsService } from './savings.service'; + +describe('SavingsService', () => { + beforeEach(() => TestBed.configureTestingModule({})); + + it('should be created', () => { + const service: SavingsService = TestBed.get(SavingsService); + expect(service).toBeTruthy(); + }); +}); diff --git a/src/app/savings/savings.service.ts b/src/app/savings/savings.service.ts new file mode 100644 index 000000000..51460e051 --- /dev/null +++ b/src/app/savings/savings.service.ts @@ -0,0 +1,34 @@ +/** Angular Imports */ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; + +/** rxjs Imports */ +import { Observable } from 'rxjs'; + +/** + * Savings Service. + */ +@Injectable({ + providedIn: 'root' +}) +export class SavingsService { + + constructor(private http: HttpClient) { } + /** + * @param {string} savingAccountId is saving account's Id. + * @returns {Observable} + */ + getSavingsTransactionTemplateResource(savingAccountId: string): Observable { + return this.http.get(`/savingsaccounts/${savingAccountId}/transactions/template`); + } + + /** + * @param {string} action transaction type. + * @param {string} savingAccountId saving account id. + * @param {any} transactionData transaction details for saving account. + * @returns {Observable} + */ + makeTransaction(action: string, savingAccountId: string, transactionData: any): Observable { + return this.http.post(`/savingsaccounts/${savingAccountId}/transactions?command=${action}`, transactionData); + } +}