diff --git a/src/app/accounting/accounting-routing.module.ts b/src/app/accounting/accounting-routing.module.ts
index 987500a55..8109221d8 100644
--- a/src/app/accounting/accounting-routing.module.ts
+++ b/src/app/accounting/accounting-routing.module.ts
@@ -4,6 +4,7 @@ import { Routes, RouterModule } from '@angular/router';
import { Route, extract } from '../core';
import { AccountingComponent } from './accounting.component';
import { FrequentPostingsComponent } from './frequent-postings/frequent-postings.component';
+import { ViewTransactionComponent } from './view-transaction/view-transaction.component';
const routes: Routes = [
Route.withShell([
@@ -19,6 +20,17 @@ const routes: Routes = [
path: 'frequent-postings',
component: FrequentPostingsComponent,
data: { title: extract('Frequent Postings'), breadcrumb: 'Frequent Postings' }
+ },
+ {
+ path: 'transactions',
+ data: { title: extract('Transactions'), breadcrumb: 'Transactions' },
+ children: [
+ {
+ path: 'view/:id',
+ component: ViewTransactionComponent,
+ data: { title: extract('View Transaction'), routeParamBreadcrumb: 'id' }
+ }
+ ]
}
]
}
diff --git a/src/app/accounting/accounting.module.ts b/src/app/accounting/accounting.module.ts
index 8ec1341fe..9aef9efb6 100644
--- a/src/app/accounting/accounting.module.ts
+++ b/src/app/accounting/accounting.module.ts
@@ -6,6 +6,9 @@ import { CoreModule } from '../core/core.module';
import { AccountingComponent } from './accounting.component';
import { AccountingRoutingModule } from './accounting-routing.module';
import { FrequentPostingsComponent } from './frequent-postings/frequent-postings.component';
+import { ViewTransactionComponent } from './view-transaction/view-transaction.component';
+import { RevertTransactionComponent } from './revert-transaction/revert-transaction.component';
+import { ViewJournalEntryComponent } from './view-journal-entry/view-journal-entry.component';
@NgModule({
imports: [
@@ -14,6 +17,16 @@ import { FrequentPostingsComponent } from './frequent-postings/frequent-postings
ReactiveFormsModule,
AccountingRoutingModule
],
- declarations: [AccountingComponent, FrequentPostingsComponent]
+ declarations: [
+ AccountingComponent,
+ FrequentPostingsComponent,
+ ViewTransactionComponent,
+ RevertTransactionComponent,
+ ViewJournalEntryComponent
+ ],
+ entryComponents: [
+ RevertTransactionComponent,
+ ViewJournalEntryComponent
+ ]
})
export class AccountingModule { }
diff --git a/src/app/accounting/accounting.service.ts b/src/app/accounting/accounting.service.ts
index bd25c549a..470b7cb14 100644
--- a/src/app/accounting/accounting.service.ts
+++ b/src/app/accounting/accounting.service.ts
@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
-import { HttpClient } from '@angular/common/http';
+import { HttpClient, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';
@Injectable({
@@ -29,5 +29,21 @@ export class AccountingService {
return this.http.post('/journalentries', journalEntry);
}
+ getJournalEntry(transactionId: string) {
+ let httpParams = new HttpParams();
+ httpParams = httpParams.set('transactionId', transactionId);
+ httpParams = httpParams.set('transactionDetails', 'true');
+ return this.http.get(`/journalentries`, { params: httpParams });
+ }
+
+ revertTransaction(transactionId: string, comments: string) {
+ let httpParams = new HttpParams();
+ httpParams = httpParams.set('command', 'reverse');
+ let data = {};
+ if (comments) {
+ data = { comments: comments };
+ }
+ return this.http.post(`/journalentries/${transactionId}`, data, { params: httpParams });
+ }
}
diff --git a/src/app/accounting/frequent-postings/frequent-postings.component.html b/src/app/accounting/frequent-postings/frequent-postings.component.html
index dbec4e327..d6fd8880b 100644
--- a/src/app/accounting/frequent-postings/frequent-postings.component.html
+++ b/src/app/accounting/frequent-postings/frequent-postings.component.html
@@ -33,7 +33,7 @@
+ *ngFor="let debit of getFormArrayData('debits').controls; let i = index;">
@@ -59,7 +59,7 @@
+ *ngFor="let credit of getFormArrayData('credits').controls; let i = index;">
diff --git a/src/app/accounting/frequent-postings/frequent-postings.component.ts b/src/app/accounting/frequent-postings/frequent-postings.component.ts
index 6a88b0709..11160db48 100644
--- a/src/app/accounting/frequent-postings/frequent-postings.component.ts
+++ b/src/app/accounting/frequent-postings/frequent-postings.component.ts
@@ -1,5 +1,6 @@
import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators, FormArray } from '@angular/forms';
+import { Router } from '@angular/router';
import { AccountingService } from '../accounting.service';
@@ -12,7 +13,6 @@ export class FrequentPostingsComponent implements OnInit {
// TODO: Validations
// https://github.com/openMF/incubator-fineract/blob/master/fineract-provider/src/main/java/org/apache/fineract/accounting/journalentry/exception/JournalEntryInvalidException.java
- // TESTING: transactionId: 8b5748a57b73
minDate = new Date(2000, 0, 1);
maxDate = new Date();
@@ -28,7 +28,8 @@ export class FrequentPostingsComponent implements OnInit {
allowMultipleDebitEntries: boolean;
constructor(private formBuilder: FormBuilder,
- private accountingService: AccountingService) { }
+ private accountingService: AccountingService,
+ private router: Router) { }
ngOnInit() {
this.createFrequentPostingsForm();
@@ -84,6 +85,10 @@ export class FrequentPostingsComponent implements OnInit {
});
}
+ getFormArrayData(type: string): FormArray {
+ return
this.frequentPostingsForm.get(type);
+ }
+
addAffectedGLEntry(affectedGLEntryFormArray: FormArray) {
affectedGLEntryFormArray.push(this.createAffectedGLEntryForm());
}
@@ -124,8 +129,7 @@ export class FrequentPostingsComponent implements OnInit {
journalEntry.dateFormat = 'dd MMMM yyyy';
journalEntry.transactionDate = '20 July 2018';
this.accountingService.createJournalEntry(journalEntry).subscribe(response => {
- console.log(response);
- // navigate to view transaction with response.transactionId
+ this.router.navigate(['/accounting/transactions/view', response.transactionId]);
});
}
diff --git a/src/app/accounting/revert-transaction/revert-transaction.component.html b/src/app/accounting/revert-transaction/revert-transaction.component.html
new file mode 100644
index 000000000..6a73b91d7
--- /dev/null
+++ b/src/app/accounting/revert-transaction/revert-transaction.component.html
@@ -0,0 +1,30 @@
+
+
+
Revert Transaction
+
+
Are you sure you want to revert this transaction?
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Transaction Reverted
+
+
Success!
+
A new journal entry has been created to reverse this transaction:
+
Transaction ID: {{ data.transactionId }}
+
+
+
+
+
+
+
diff --git a/src/app/accounting/revert-transaction/revert-transaction.component.scss b/src/app/accounting/revert-transaction/revert-transaction.component.scss
new file mode 100644
index 000000000..e69de29bb
diff --git a/src/app/accounting/revert-transaction/revert-transaction.component.spec.ts b/src/app/accounting/revert-transaction/revert-transaction.component.spec.ts
new file mode 100644
index 000000000..342e3e465
--- /dev/null
+++ b/src/app/accounting/revert-transaction/revert-transaction.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { RevertTransactionComponent } from './revert-transaction.component';
+
+describe('RevertTransactionComponent', () => {
+ let component: RevertTransactionComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ RevertTransactionComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(RevertTransactionComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/accounting/revert-transaction/revert-transaction.component.ts b/src/app/accounting/revert-transaction/revert-transaction.component.ts
new file mode 100644
index 000000000..79579f74d
--- /dev/null
+++ b/src/app/accounting/revert-transaction/revert-transaction.component.ts
@@ -0,0 +1,20 @@
+import { Component, OnInit, Inject } from '@angular/core';
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
+import { FormControl } from '@angular/forms';
+
+@Component({
+ selector: 'mifosx-revert-transaction',
+ templateUrl: './revert-transaction.component.html',
+ styleUrls: ['./revert-transaction.component.scss']
+})
+export class RevertTransactionComponent implements OnInit {
+
+ comments = new FormControl('');
+
+ constructor(public dialogRef: MatDialogRef,
+ @Inject(MAT_DIALOG_DATA) public data: any) { }
+
+ ngOnInit() {
+ }
+
+}
diff --git a/src/app/accounting/view-journal-entry/view-journal-entry.component.html b/src/app/accounting/view-journal-entry/view-journal-entry.component.html
new file mode 100644
index 000000000..ecc8d79ca
--- /dev/null
+++ b/src/app/accounting/view-journal-entry/view-journal-entry.component.html
@@ -0,0 +1,108 @@
+View Journal Entry
+
+
+
+
+ | Office |
+ {{ data.journalEntry.officeName }} |
+
+
+
+ | Entry ID |
+ {{ data.journalEntry.id }} |
+
+
+
+ | Transaction ID |
+ {{ data.journalEntry.transactionId }} |
+
+
+
+ | Transaction Date |
+ {{ data.journalEntry.transactionDate }} |
+
+
+
+ | Type |
+ {{ data.journalEntry.glAccountType.value }} |
+
+
+
+ | Account Code |
+ {{ data.journalEntry.glAccountId }} |
+
+
+
+ | Account Name |
+ {{ data.journalEntry.glAccountName }} |
+
+
+
+ |
+ Credit
+ Debit
+ |
+
+ {{ (data.journalEntry.currency.displaySymbol || data.journalEntry.currency.code) + ' ' + data.journalEntry.amount }}
+ |
+
+
+
+ | Reference Number |
+ {{ data.journalEntry.referenceNumber }} |
+
+
+
+ | Comments |
+ {{ data.journalEntry.comments }} |
+
+
+
+
+
+
+
+ | Payment Type |
+ {{ data.journalEntry.transactionDetails.paymentDetails.paymentType.name }} |
+
+
+
+ | Account Number |
+ {{ data.journalEntry.transactionDetails.paymentDetails.accountNumber }} |
+
+
+
+ | Cheque Number |
+ {{ data.journalEntry.transactionDetails.paymentDetails.checkNumber }} |
+
+
+
+ | Routing Code |
+ {{ data.journalEntry.transactionDetails.paymentDetails.routingCode }} |
+
+
+
+ | Receipt Number |
+ {{ data.journalEntry.transactionDetails.paymentDetails.receiptNumber }} |
+
+
+
+ | Bank Number |
+ {{ data.journalEntry.transactionDetails.paymentDetails.bankNumber }} |
+
+
+
+ | Created by |
+ {{ data.journalEntry.createdByUserName }} |
+
+
+
+ | Created on |
+ {{ data.journalEntry.createdDate }} |
+
+
+
+
+
+
+
diff --git a/src/app/accounting/view-journal-entry/view-journal-entry.component.scss b/src/app/accounting/view-journal-entry/view-journal-entry.component.scss
new file mode 100644
index 000000000..d8a0b3c67
--- /dev/null
+++ b/src/app/accounting/view-journal-entry/view-journal-entry.component.scss
@@ -0,0 +1,13 @@
+th {
+ text-align: left;
+ font-weight: 500;
+}
+
+th, td {
+ padding: 0 0.4rem 0 0;
+}
+
+.header {
+ text-align: center;
+ padding: 0.4rem 0.4rem 0 0;
+}
diff --git a/src/app/accounting/view-journal-entry/view-journal-entry.component.spec.ts b/src/app/accounting/view-journal-entry/view-journal-entry.component.spec.ts
new file mode 100644
index 000000000..30c10fb32
--- /dev/null
+++ b/src/app/accounting/view-journal-entry/view-journal-entry.component.spec.ts
@@ -0,0 +1,25 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ViewJournalEntryComponent } from './view-journal-entry.component';
+
+describe('ViewJournalEntryComponent', () => {
+ let component: ViewJournalEntryComponent;
+ let fixture: ComponentFixture;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ ViewJournalEntryComponent ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ViewJournalEntryComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/src/app/accounting/view-journal-entry/view-journal-entry.component.ts b/src/app/accounting/view-journal-entry/view-journal-entry.component.ts
new file mode 100644
index 000000000..949b7bfe9
--- /dev/null
+++ b/src/app/accounting/view-journal-entry/view-journal-entry.component.ts
@@ -0,0 +1,17 @@
+import { Component, OnInit, Inject } from '@angular/core';
+import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material';
+
+@Component({
+ selector: 'mifosx-view-journal-entry',
+ templateUrl: './view-journal-entry.component.html',
+ styleUrls: ['./view-journal-entry.component.scss']
+})
+export class ViewJournalEntryComponent implements OnInit {
+
+ constructor(public dialogRef: MatDialogRef,
+ @Inject(MAT_DIALOG_DATA) public data: any) { }
+
+ ngOnInit() {
+ }
+
+}
diff --git a/src/app/accounting/view-transaction/view-transaction.component.html b/src/app/accounting/view-transaction/view-transaction.component.html
new file mode 100644
index 000000000..4a00272eb
--- /dev/null
+++ b/src/app/accounting/view-transaction/view-transaction.component.html
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ dataSource.data[0].officeName }}
+
+
+
+
+
+ {{ dataSource.data[0].transactionDate }}
+
+
+
+
+
+ {{ dataSource.data[0].createdByUserName }}
+
+
+
+
+
+ {{ dataSource.data[0].createdDate }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ | Entry ID |
+ {{ transaction.id }} |
+
+
+
+ Type |
+ {{ transaction.glAccountType.value }} |
+
+
+
+ Account Code |
+ {{ transaction.glAccountCode }} |
+
+
+
+ Account Name |
+ {{ transaction.glAccountName }} |
+
+
+
+ Debit |
+ {{ (transaction.currency.displaySymbol || transaction.currency.code) + ' ' + transaction.amount }} |
+
+
+
+ Credit |
+ {{ (transaction.currency.displaySymbol || transaction.currency.code) + ' ' + transaction.amount }} |
+
+
+
+
+
+
+
+
+
+
diff --git a/src/app/accounting/view-transaction/view-transaction.component.scss b/src/app/accounting/view-transaction/view-transaction.component.scss
new file mode 100644
index 000000000..fff2afccc
--- /dev/null
+++ b/src/app/accounting/view-transaction/view-transaction.component.scss
@@ -0,0 +1,17 @@
+.content {
+ div {
+ line-height: 3rem;
+ }
+
+ .header {
+ font-weight: 500;
+ }
+}
+
+table {
+ width: 100%;
+}
+
+.select:hover {
+ cursor: pointer;
+}
diff --git a/src/app/accounting/view-transaction/view-transaction.component.spec.ts b/src/app/accounting/view-transaction/view-transaction.component.spec.ts
new file mode 100644
index 000000000..bbff0d11b
--- /dev/null
+++ b/src/app/accounting/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/accounting/view-transaction/view-transaction.component.ts b/src/app/accounting/view-transaction/view-transaction.component.ts
new file mode 100644
index 000000000..4520a31c8
--- /dev/null
+++ b/src/app/accounting/view-transaction/view-transaction.component.ts
@@ -0,0 +1,79 @@
+import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core';
+import { ActivatedRoute, Router, ParamMap } from '@angular/router';
+import { MatDialog, MatSort, MatPaginator, MatTableDataSource } from '@angular/material';
+
+import { AccountingService } from '../accounting.service';
+import { RevertTransactionComponent } from '../revert-transaction/revert-transaction.component';
+import { ViewJournalEntryComponent } from '../view-journal-entry/view-journal-entry.component';
+
+@Component({
+ selector: 'mifosx-view-transaction',
+ templateUrl: './view-transaction.component.html',
+ styleUrls: ['./view-transaction.component.scss']
+})
+export class ViewTransactionComponent implements OnInit, OnDestroy {
+
+ // TODO: Update once language and date settings are setup
+ transactionId: string;
+ transactionId$: any;
+ displayedColumns: string[] = ['id', 'glAccountType', 'glAccountCode', 'glAccountName', 'debit', 'credit'];
+ dataSource: any;
+
+ @ViewChild(MatPaginator) paginator: MatPaginator;
+ @ViewChild(MatSort) sort: MatSort;
+
+ constructor(private route: ActivatedRoute,
+ private router: Router,
+ private accountingService: AccountingService,
+ public dialog: MatDialog) { }
+
+ ngOnInit() {
+ this.transactionId$ = this.route.paramMap.subscribe((params: ParamMap) => {
+ this.transactionId = params.get('id');
+ this.getJournalEntry();
+ });
+ }
+
+ getJournalEntry() {
+ this.accountingService.getJournalEntry(this.transactionId).subscribe((journalEntry: any) => {
+ this.dataSource = new MatTableDataSource(journalEntry.pageItems);
+ this.dataSource.paginator = this.paginator;
+ this.dataSource.sortingDataAccessor = (transaction: any, property: any) => {
+ switch (property) {
+ case 'glAccountType': return transaction.glAccountType.value;
+ case 'debit': return transaction.amount;
+ case 'credit': return transaction.amount;
+ default: return transaction[property];
+ }
+ };
+ this.dataSource.sort = this.sort;
+ });
+ }
+
+ viewJournalEntry(journalEntry: any) {
+ this.dialog.open(ViewJournalEntryComponent, {
+ data: { journalEntry: journalEntry }
+ });
+ }
+
+ revertTransaction(transactionId?: string) {
+ const revertTransactionDialogRef = this.dialog.open(RevertTransactionComponent, {
+ data: { reverted: this.dataSource.data[0].reversed, transactionId: transactionId }
+ });
+ revertTransactionDialogRef.afterClosed().subscribe((response: any) => {
+ if (response.revert) {
+ this.accountingService.revertTransaction(this.transactionId, response.comments).subscribe((reversedTransaction: any) => {
+ this.dataSource.data[0].reversed = true;
+ this.revertTransaction(reversedTransaction.transactionId);
+ });
+ } else if (response.redirect) {
+ this.router.navigate(['/accounting/transactions/view', transactionId]);
+ }
+ });
+ }
+
+ ngOnDestroy() {
+ this.transactionId$.unsubscribe();
+ }
+
+}