From 347e84f366afa332d404d0d6f6c552aabda4a1e6 Mon Sep 17 00:00:00 2001 From: Abhijeet Singh Date: Sun, 7 Jun 2020 22:57:18 +0530 Subject: [PATCH] feat: add savings charge form (#726) Fixes: #250 --- src/app/clients/clients-routing.module.ts | 5 + .../add-savings-charge.component.html | 93 ++++++++++++ .../add-savings-charge.component.scss | 3 + .../add-savings-charge.component.spec.ts | 25 ++++ .../add-savings-charge.component.ts | 138 ++++++++++++++++++ .../savings-charge-template.resolver.ts | 30 ++++ src/app/savings/savings-routing.module.ts | 62 +++++--- src/app/savings/savings.module.ts | 6 +- src/app/savings/savings.service.ts | 28 +++- 9 files changed, 362 insertions(+), 28 deletions(-) create mode 100644 src/app/savings/add-savings-charge/add-savings-charge.component.html create mode 100644 src/app/savings/add-savings-charge/add-savings-charge.component.scss create mode 100644 src/app/savings/add-savings-charge/add-savings-charge.component.spec.ts create mode 100644 src/app/savings/add-savings-charge/add-savings-charge.component.ts create mode 100644 src/app/savings/common-resolvers/savings-charge-template.resolver.ts diff --git a/src/app/clients/clients-routing.module.ts b/src/app/clients/clients-routing.module.ts index 21f40c5ab..f84a683c6 100644 --- a/src/app/clients/clients-routing.module.ts +++ b/src/app/clients/clients-routing.module.ts @@ -49,6 +49,11 @@ const routes: Routes = [ path: '', component: ClientsComponent, }, + { + path: ':clientId/savingsaccounts', + data: { routeParamBreadcrumb: 'clientId'}, + loadChildren: '../savings/savings.module#SavingsModule' + }, { path: ':clientId', component: ClientsViewComponent, diff --git a/src/app/savings/add-savings-charge/add-savings-charge.component.html b/src/app/savings/add-savings-charge/add-savings-charge.component.html new file mode 100644 index 000000000..6bcfb3ae0 --- /dev/null +++ b/src/app/savings/add-savings-charge/add-savings-charge.component.html @@ -0,0 +1,93 @@ +
+ + + +
+ + + +
+ + Charge + + + {{ savingsCharge.name + ' (' + savingsCharge.currency.name + ')' }} + + + + Charge is required + + + +
+ + + Amount + + + Amount is required + + + + + Charge Calculation + + + {{ chargeCalculation.value }} + + + + + + Charge time type + + + {{ chargeTime.value }} + + + + + + Due for collection on + + + + + Due for collection on is required + + + + + Due On + + + + + Due Date is required + + + + + Repeats Every + + + +
+ +
+ + + + + + +
+ +
+ +
+ +
diff --git a/src/app/savings/add-savings-charge/add-savings-charge.component.scss b/src/app/savings/add-savings-charge/add-savings-charge.component.scss new file mode 100644 index 000000000..1cbc977c5 --- /dev/null +++ b/src/app/savings/add-savings-charge/add-savings-charge.component.scss @@ -0,0 +1,3 @@ +.container{ + width: 37rem; +} diff --git a/src/app/savings/add-savings-charge/add-savings-charge.component.spec.ts b/src/app/savings/add-savings-charge/add-savings-charge.component.spec.ts new file mode 100644 index 000000000..316b6be53 --- /dev/null +++ b/src/app/savings/add-savings-charge/add-savings-charge.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AddSavingsChargeComponent } from './add-savings-charge.component'; + +describe('AddSavingsChargeComponent', () => { + let component: AddSavingsChargeComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ AddSavingsChargeComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(AddSavingsChargeComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/savings/add-savings-charge/add-savings-charge.component.ts b/src/app/savings/add-savings-charge/add-savings-charge.component.ts new file mode 100644 index 000000000..61f995e56 --- /dev/null +++ b/src/app/savings/add-savings-charge/add-savings-charge.component.ts @@ -0,0 +1,138 @@ +/** 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'; + +/** + * Add Savings Charge component. + */ +@Component({ + selector: 'mifosx-add-savings-charge', + templateUrl: './add-savings-charge.component.html', + styleUrls: ['./add-savings-charge.component.scss'] +}) +export class AddSavingsChargeComponent implements OnInit { + + /** Minimum Due Date allowed. */ + minDate = new Date(2000, 0, 1); + /** Maximum Due Date allowed. */ + maxDate = new Date(); + /** Add Savings Charge form. */ + savingsChargeForm: FormGroup; + /** savings charge options. */ + savingsChargeOptions: any; + /** savings Id of the savings account. */ + savingAccountId: string; + /** charge details */ + chargeDetails: any; + + /** + * Retrieves the savings charge template data from `resolve`. + * @param {FormBuilder} formBuilder Form Builder. + * @param {AccountingService} accountingService Accounting Service. + * @param {ActivatedRoute} route Activated Route. + * @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: { savingsChargeTemplate: any }) => { + this.savingsChargeOptions = data.savingsChargeTemplate.chargeOptions; + }); + this.savingAccountId = this.route.snapshot.params['savingAccountId']; + } + + /** + * Creates the Savings Charge form. + */ + ngOnInit() { + this.createSavingsChargeForm(); + this.buildDependencies(); + } + + buildDependencies() { + this.savingsChargeForm.controls.chargeId.valueChanges.subscribe(chargeId => { + this.savingsService.getChargeTemplate(chargeId).subscribe((data: any) => { + this.chargeDetails = data; + const chargeTimeType = data.chargeTimeType.id; + if (data.chargeTimeType.value === 'Withdrawal Fee' || data.chargeTimeType.value === 'Saving No Activity Fee') { + this.chargeDetails.dueDateNotRequired = true; + } + if (data.chargeTimeType.value === 'Annual Fee' || data.chargeTimeType.value === 'Monthly Fee') { + this.chargeDetails.chargeTimeTypeAnnualOrMonth = true; + } + if (!this.chargeDetails.dueDateNotRequired && !this.chargeDetails.chargeTimeTypeAnnualOrMonth) { + this.savingsChargeForm.addControl('dueDate', new FormControl('', Validators.required)); + } else { + this.savingsChargeForm.removeControl('dueDate'); + } + if (!this.chargeDetails.dueDateNotRequired && this.chargeDetails.chargeTimeTypeAnnualOrMonth) { + this.savingsChargeForm.addControl('feeOnMonthDay', new FormControl('', Validators.required)); + } else { + this.savingsChargeForm.removeControl('feeOnMonthDay'); + } + if (chargeTimeType.value === 'Monthly Fee') { + this.savingsChargeForm.addControl('feeInterval', new FormControl(data.feeInterval, Validators.required)); + } else { + this.savingsChargeForm.removeControl('feeInterval'); + } + this.savingsChargeForm.patchValue({ + 'amount': data.amount, + 'chargeCalculationType': data.chargeCalculationType.id, + 'chargeTimeType': data.chargeTimeType.id + }); + }); + }); + } + + /** + * Creates the Savings Charge form. + */ + createSavingsChargeForm() { + this.savingsChargeForm = this.formBuilder.group({ + 'chargeId': ['', Validators.required], + 'amount': ['', Validators.required], + 'chargeCalculationType': [{ value: '', disabled: true }], + 'chargeTimeType': [{ value: '', disabled: true }] + }); + } + + /** + * Submits savings charge. + */ + submit() { + const savingsCharge = this.savingsChargeForm.value; + savingsCharge.locale = 'en'; + if (!savingsCharge.feeInterval) { + savingsCharge.feeInterval = this.chargeDetails.feeInterval; + } + if (this.chargeDetails.dueDateNotRequired !== true) { + if (this.chargeDetails.chargeTimeTypeAnnualOrMonth === true) { + const monthDayFormat = 'MMMM-dd'; // TODO: Update once language and date settings are setup + savingsCharge.monthDayFormat = monthDayFormat; + if (savingsCharge.feeOnMonthDay) { + const prevDate = this.savingsChargeForm.value.feeOnMonthDay; + savingsCharge.feeOnMonthDay = this.datePipe.transform(prevDate, monthDayFormat); + } + } else { + const dateFormat = 'yyyy-MM-dd'; + savingsCharge.dateFormat = dateFormat; + if (savingsCharge.dueDate) { + const prevDate = this.savingsChargeForm.value.dueDate; + savingsCharge.dueDate = this.datePipe.transform(prevDate, dateFormat); + } + } + } + this.savingsService.createSavingsCharge(this.savingAccountId, 'charges', savingsCharge).subscribe(res => { + // this.router.navigate(['../'], { relativeTo: this.route }); + }); + } +} diff --git a/src/app/savings/common-resolvers/savings-charge-template.resolver.ts b/src/app/savings/common-resolvers/savings-charge-template.resolver.ts new file mode 100644 index 000000000..e9d1c485b --- /dev/null +++ b/src/app/savings/common-resolvers/savings-charge-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 Charge Template data resolver. + */ +@Injectable() +export class SavingsChargeTemplateResolver implements Resolve { + + /** + * @param {SavingsService} SavingsService savings service. + */ + constructor(private savingsService: SavingsService) {} + + /** + * Returns the Savings Charge Template. + * @returns {Observable} + */ + resolve(route: ActivatedRouteSnapshot): Observable { + const savingAccountId = route.paramMap.get('savingAccountId'); + return this.savingsService.getSavingsChargeTemplateResource(savingAccountId); + } +} diff --git a/src/app/savings/savings-routing.module.ts b/src/app/savings/savings-routing.module.ts index e01a17386..387d93dd7 100644 --- a/src/app/savings/savings-routing.module.ts +++ b/src/app/savings/savings-routing.module.ts @@ -7,38 +7,52 @@ import { extract } from '../core/i18n/i18n.service'; /** Custom Components */ import { SavingAccountActionsComponent } from './saving-account-actions/saving-account-actions.component'; +import { AddSavingsChargeComponent } from './add-savings-charge/add-savings-charge.component'; /** Custom Resolvers */ import { SavingAccountTransactionTemplateResolver } from './common-resolvers/saving-transaction-template.resolver'; +import { SavingsChargeTemplateResolver } from './common-resolvers/savings-charge-template.resolver'; const routes: Routes = [ - { - path: '', - data: { title: extract('All Savings'), breadcrumb: 'Savings', routeParamBreadcrumb: false }, - // Component to view all saving accounts Comes Here + { + 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: ':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 - } - } - ] + { + path: 'add-savings-charge', + component: AddSavingsChargeComponent, + data: { + title: extract('Add Savings Charge'), + breadcrumb: 'Add Savings Charge', + routeParamBreadcrumb: false + }, + resolve: { + savingsChargeTemplate: SavingsChargeTemplateResolver } + }, + { + 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] + imports: [RouterModule.forChild(routes)], + exports: [RouterModule], + declarations: [], + providers: [SavingAccountTransactionTemplateResolver, SavingsChargeTemplateResolver] }) -export class SavingsRoutingModule { } +export class SavingsRoutingModule {} diff --git a/src/app/savings/savings.module.ts b/src/app/savings/savings.module.ts index e85124628..3cabcde2d 100644 --- a/src/app/savings/savings.module.ts +++ b/src/app/savings/savings.module.ts @@ -9,6 +9,7 @@ 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'; +import { AddSavingsChargeComponent } from './add-savings-charge/add-savings-charge.component'; /** * Savings Module @@ -22,8 +23,9 @@ import { SavingsAccountTransactionsComponent } from './saving-account-actions/sa ], declarations: [ SavingAccountActionsComponent, - SavingsAccountTransactionsComponent + SavingsAccountTransactionsComponent, + AddSavingsChargeComponent ], providers: [DatePipe] }) -export class SavingsModule { } +export class SavingsModule {} diff --git a/src/app/savings/savings.service.ts b/src/app/savings/savings.service.ts index 51460e051..59cc011b9 100644 --- a/src/app/savings/savings.service.ts +++ b/src/app/savings/savings.service.ts @@ -12,8 +12,7 @@ import { Observable } from 'rxjs'; providedIn: 'root' }) export class SavingsService { - - constructor(private http: HttpClient) { } + constructor(private http: HttpClient) {} /** * @param {string} savingAccountId is saving account's Id. * @returns {Observable} @@ -31,4 +30,29 @@ export class SavingsService { makeTransaction(action: string, savingAccountId: string, transactionData: any): Observable { return this.http.post(`/savingsaccounts/${savingAccountId}/transactions?command=${action}`, transactionData); } + + /** + * @param {string} savingAccountId saving account id. + * @returns {Observable} + */ + getSavingsChargeTemplateResource(savingAccountId: string): Observable { + return this.http.get(`/savingsaccounts/${savingAccountId}/charges/template`); + } + + /** + * @param {any} savingsCharge to apply on a savings Account. + * @returns {Observable} + */ + createSavingsCharge(savingAccountId: string, resourceType: string, savingsCharge: any): Observable { + return this.http.post(`/savingsaccounts/${savingAccountId}/${resourceType}`, savingsCharge); + } + + /** + * @param {string} chargeId Charge ID of charge. + * @returns {Observable} Charge. + */ + getChargeTemplate(chargeId: string): Observable { + const params = { template: 'true' }; + return this.http.get(`/charges/${chargeId}`, { params: params }); + } }