diff --git a/src/app/savings/common-resolvers/savings-account-transaction.resolver.ts b/src/app/savings/common-resolvers/savings-account-transaction.resolver.ts new file mode 100644 index 000000000..f30c75545 --- /dev/null +++ b/src/app/savings/common-resolvers/savings-account-transaction.resolver.ts @@ -0,0 +1,33 @@ +/** 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 data resolver. + */ +@Injectable() +export class SavingsAccountTransactionResolver implements Resolve { + + /** + * @param {SavingsService} SavingsService Savings service. + */ + constructor(private savingsService: SavingsService) { } + + /** + * Returns the Savings Account Transaction data. + * @param {ActivatedRouteSnapshot} route Route Snapshot + * @returns {Observable} + */ + resolve(route: ActivatedRouteSnapshot): Observable { + const savingAccountId = route.parent.paramMap.get('savingAccountId'); + const transactionId = route.paramMap.get('id'); + return this.savingsService.getSavingsAccountTransaction(savingAccountId, transactionId); + } + +} diff --git a/src/app/savings/savings-account-view/custom-dialogs/undo-transaction-dialog/undo-transaction-dialog.component.html b/src/app/savings/savings-account-view/custom-dialogs/undo-transaction-dialog/undo-transaction-dialog.component.html new file mode 100644 index 000000000..688f28271 --- /dev/null +++ b/src/app/savings/savings-account-view/custom-dialogs/undo-transaction-dialog/undo-transaction-dialog.component.html @@ -0,0 +1,8 @@ +

Undo Transaction

+
+

Are you sure you want to undo this transaction ?

+
+ + + + diff --git a/src/app/savings/savings-account-view/custom-dialogs/undo-transaction-dialog/undo-transaction-dialog.component.scss b/src/app/savings/savings-account-view/custom-dialogs/undo-transaction-dialog/undo-transaction-dialog.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/src/app/savings/savings-account-view/custom-dialogs/undo-transaction-dialog/undo-transaction-dialog.component.spec.ts b/src/app/savings/savings-account-view/custom-dialogs/undo-transaction-dialog/undo-transaction-dialog.component.spec.ts new file mode 100644 index 000000000..dbc966965 --- /dev/null +++ b/src/app/savings/savings-account-view/custom-dialogs/undo-transaction-dialog/undo-transaction-dialog.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UndoTransactionDialogComponent } from './undo-transaction-dialog.component'; + +describe('UndoTransactionDialogComponent', () => { + let component: UndoTransactionDialogComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ UndoTransactionDialogComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(UndoTransactionDialogComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/savings/savings-account-view/custom-dialogs/undo-transaction-dialog/undo-transaction-dialog.component.ts b/src/app/savings/savings-account-view/custom-dialogs/undo-transaction-dialog/undo-transaction-dialog.component.ts new file mode 100644 index 000000000..07720213b --- /dev/null +++ b/src/app/savings/savings-account-view/custom-dialogs/undo-transaction-dialog/undo-transaction-dialog.component.ts @@ -0,0 +1,20 @@ +/** Angular Imports */ +import { Component } from '@angular/core'; +import { MatDialogRef } from '@angular/material'; + +/** + * Undo transaction dialog component. + */ +@Component({ + selector: 'mifosx-undo-transaction-dialog', + templateUrl: './undo-transaction-dialog.component.html', + styleUrls: ['./undo-transaction-dialog.component.scss'] +}) +export class UndoTransactionDialogComponent { + + /** + * @param {MatDialogRef} dialogRef Component reference to dialog. + */ + constructor(public dialogRef: MatDialogRef) { } + +} 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 index 1be786c3b..a8e415ebb 100644 --- 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 @@ -54,7 +54,7 @@ - + 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 index ad2bc9bd7..ae859ea89 100644 --- 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 @@ -15,5 +15,8 @@ margin: 0 10%; line-height: 25px; } + .select-row:hover { + cursor: pointer; + } } } 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 index d6d68d3ae..45b485a02 100644 --- 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 @@ -28,7 +28,7 @@ export class TransactionsTabComponent implements OnInit { */ constructor(private route: ActivatedRoute) { this.route.parent.data.subscribe((data: { savingsAccountData: any }) => { - this.transactionsData = data.savingsAccountData.transactions; + this.transactionsData = data.savingsAccountData.transactions.filter((transaction: any) => !transaction.reversed); this.status = data.savingsAccountData.status.value; }); } diff --git a/src/app/savings/savings-account-view/view-transaction/view-transaction.component.html b/src/app/savings/savings-account-view/view-transaction/view-transaction.component.html new file mode 100644 index 000000000..bc9528fed --- /dev/null +++ b/src/app/savings/savings-account-view/view-transaction/view-transaction.component.html @@ -0,0 +1,64 @@ +
+ +
+ +
+ + + + + +
+ +
+ Transaction Id +
+ +
+ {{ transactionData.id }} +
+ +
+ Type +
+ +
+ {{ transactionData.transactionType.value }} +
+ +
+ Transaction Date +
+ +
+ {{ transactionData.date | date }} +
+ +
+ Currency +
+ +
+ {{ transactionData.currency.displayLabel }} +
+ +
+ Amount +
+ +
+ {{ transactionData.amount }} +
+ +
+ +
+ +
+ +
diff --git a/src/app/savings/savings-account-view/view-transaction/view-transaction.component.scss b/src/app/savings/savings-account-view/view-transaction/view-transaction.component.scss new file mode 100644 index 000000000..56668f14f --- /dev/null +++ b/src/app/savings/savings-account-view/view-transaction/view-transaction.component.scss @@ -0,0 +1,10 @@ +.container { + max-width: 37rem; + + .content { + div { + margin: 1rem 0; + word-wrap: break-word; + } + } +} diff --git a/src/app/savings/savings-account-view/view-transaction/view-transaction.component.spec.ts b/src/app/savings/savings-account-view/view-transaction/view-transaction.component.spec.ts new file mode 100644 index 000000000..bbff0d11b --- /dev/null +++ b/src/app/savings/savings-account-view/view-transaction/view-transaction.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ViewTransactionComponent } from './view-transaction.component'; + +describe('ViewTransactionComponent', () => { + let component: ViewTransactionComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ViewTransactionComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ViewTransactionComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/savings/savings-account-view/view-transaction/view-transaction.component.ts b/src/app/savings/savings-account-view/view-transaction/view-transaction.component.ts new file mode 100644 index 000000000..3802075f7 --- /dev/null +++ b/src/app/savings/savings-account-view/view-transaction/view-transaction.component.ts @@ -0,0 +1,67 @@ +/** Angular Imports */ +import { Component } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { MatDialog } from '@angular/material'; +import { DatePipe } from '@angular/common'; + +/** Custom Services */ +import { SavingsService } from 'app/savings/savings.service'; + +/** Custom Dialogs */ +import { UndoTransactionDialogComponent } from '../custom-dialogs/undo-transaction-dialog/undo-transaction-dialog.component'; + +/** + * View Transaction Component. + */ +@Component({ + selector: 'mifosx-view-transaction', + templateUrl: './view-transaction.component.html', + styleUrls: ['./view-transaction.component.scss'] +}) +export class ViewTransactionComponent { + + /** Transaction data. */ + transactionData: any; + + /** + * Retrieves the Transaction data from `resolve`. + * @param {SavingsService} savingsService Savings Service + * @param {ActivatedRoute} route Activated Route. + * @param {Router} router Router for navigation. + * @param {MatDialog} dialog Dialog reference. + * @param {DatePipe} datePipe DatePipe. + */ + constructor(private savingsService: SavingsService, + private route: ActivatedRoute, + private datePipe: DatePipe, + private router: Router, + public dialog: MatDialog) { + this.route.data.subscribe((data: { savingsAccountTransaction: any }) => { + this.transactionData = data.savingsAccountTransaction; + }); + } + + /** + * Undo the savings transaction + */ + undoTransaction() { + const accountId = this.route.parent.snapshot.params['savingAccountId']; + const undoTransactionAccountDialogRef = this.dialog.open(UndoTransactionDialogComponent); + undoTransactionAccountDialogRef.afterClosed().subscribe((response: any) => { + if (response.confirm) { + const locale = 'en'; + const dateFormat = 'dd MMMM yyyy'; + const data = { + transactionDate: this.datePipe.transform(this.transactionData.date && new Date(this.transactionData.date), dateFormat), + transactionAmount: 0, + dateFormat, + locale + }; + this.savingsService.executeSavingsAccountTransactionsCommand(accountId, 'undo', data, this.transactionData.id).subscribe(() => { + this.router.navigate(['../'], { relativeTo: this.route }); + }); + } + }); + } + +} diff --git a/src/app/savings/savings-routing.module.ts b/src/app/savings/savings-routing.module.ts index 16c2f370b..549b386c6 100644 --- a/src/app/savings/savings-routing.module.ts +++ b/src/app/savings/savings-routing.module.ts @@ -15,6 +15,7 @@ import { StandingInstructionsTabComponent } from './savings-account-view/standin import { DatatableTabsComponent } from './savings-account-view/datatable-tabs/datatable-tabs.component'; import { CreateSavingsAccountComponent } from './create-savings-account/create-savings-account.component'; import { EditSavingsAccountComponent } from './edit-savings-account/edit-savings-account.component'; +import { ViewTransactionComponent } from './savings-account-view/view-transaction/view-transaction.component'; /** Custom Resolvers */ import { SavingAccountTransactionTemplateResolver } from './common-resolvers/saving-transaction-template.resolver'; @@ -24,6 +25,7 @@ import { SavingsDatatableResolver } from './common-resolvers/savings-datatable.r import { SavingsDatatablesResolver } from './common-resolvers/savings-datatables.resolver'; import { SavingsAccountTemplateResolver } from './common-resolvers/savings-account-template.resolver'; import { SavingsAccountAndTemplateResolver } from './common-resolvers/savings-account-and-template.resolver'; +import { SavingsAccountTransactionResolver } from './common-resolvers/savings-account-transaction.resolver'; const routes: Routes = [ { @@ -88,6 +90,24 @@ const routes: Routes = [ savingsAccountAndTemplate: SavingsAccountAndTemplateResolver } }, + { + path: 'transactions', + data: { title: extract('Savings Account Transactions'), breadcrumb: 'Transactions', routeParamBreadcrumb: false }, + children: [ + { + path: '', + redirectTo: '../transactions', pathMatch: 'prefix' + }, + { + path: ':id', + data: { routeParamBreadcrumb: 'id' }, + component: ViewTransactionComponent, + resolve: { + savingsAccountTransaction: SavingsAccountTransactionResolver + } + } + ] + }, { path: 'actions/:name', data: { title: extract('Savings Account Actions'), routeParamBreadcrumb: 'name' }, @@ -108,6 +128,7 @@ const routes: Routes = [ SavingsDatatablesResolver, SavingsDatatableResolver, SavingsAccountTemplateResolver, - SavingsAccountAndTemplateResolver] + SavingsAccountAndTemplateResolver, + SavingsAccountTransactionResolver] }) export class SavingsRoutingModule {} diff --git a/src/app/savings/savings.module.ts b/src/app/savings/savings.module.ts index 2f005d324..e334fab47 100644 --- a/src/app/savings/savings.module.ts +++ b/src/app/savings/savings.module.ts @@ -35,6 +35,8 @@ import { SavingsAccountAssignStaffComponent } from './saving-account-actions/sav import { SavingsAccountUnassignStaffComponent } from './saving-account-actions/savings-account-unassign-staff/savings-account-unassign-staff.component'; import { CalculateInterestDialogComponent } from './savings-account-view/custom-dialogs/calculate-interest-dialog/calculate-interest-dialog.component'; import { PostInterestDialogComponent } from './savings-account-view/custom-dialogs/post-interest-dialog/post-interest-dialog.component'; +import { ViewTransactionComponent } from './savings-account-view/view-transaction/view-transaction.component'; +import { UndoTransactionDialogComponent } from './savings-account-view/custom-dialogs/undo-transaction-dialog/undo-transaction-dialog.component'; /** * Savings Module @@ -74,11 +76,14 @@ import { PostInterestDialogComponent } from './savings-account-view/custom-dialo SavingsAccountAssignStaffComponent, SavingsAccountUnassignStaffComponent, CalculateInterestDialogComponent, - PostInterestDialogComponent + PostInterestDialogComponent, + ViewTransactionComponent, + UndoTransactionDialogComponent ], entryComponents: [ CalculateInterestDialogComponent, - PostInterestDialogComponent + PostInterestDialogComponent, + UndoTransactionDialogComponent ], providers: [DatePipe] }) diff --git a/src/app/savings/savings.service.ts b/src/app/savings/savings.service.ts index 9e2fb7461..519ce3708 100644 --- a/src/app/savings/savings.service.ts +++ b/src/app/savings/savings.service.ts @@ -194,14 +194,25 @@ export class SavingsService { return this.http.post(`/savingsaccounts/${accountId}`, data, { params: httpParams }); } + /** + * @param {string} accountId Savings Account Id + * @param {string} transactionId Transaction Id + */ + getSavingsAccountTransaction(accountId: string, transactionId: string) { + return this.http.get(`/savingsaccounts/${accountId}/transactions/${transactionId}`); + } + /** * @param {string} accountId Savings Account Id * @param {string} command Command * @param {any} data Data * @returns {Observable} Savings data. */ - executeSavingsAccountTransactionsCommand(accountId: string, command: string, data: any): Observable { + executeSavingsAccountTransactionsCommand(accountId: string, command: string, data: any, transactionId?: any): Observable { const httpParams = new HttpParams().set('command', command); + if (transactionId) { + return this.http.post(`/savingsaccounts/${accountId}/transactions/${transactionId}`, data, { params: httpParams }); + } return this.http.post(`/savingsaccounts/${accountId}/transactions`, data, { params: httpParams }); }